From: Nicolas Neuss
Subject: `#2a((1.0))
Date: 
Message-ID: <87k6z0jx6t.fsf@ortler.iwr.uni-heidelberg.de>
Hello,

Using CMUCL:

1. (let ((x 1)) `#(,x))  => #(1)

2. The following does not yield #2a((1)) but 

(let ((x 1)) `#2a((,x)))  => #2A((((LISP::|,|) . X)))

(CLISP gives an error here)

Questions: Is the code in (1) or (2) legal?  Should (2) work?

My actual problem is the following: I have written a reader macro #m for
reading in matrices as follows

  (set-dispatch-macro-character
   #\# #\m 
   #'(lambda (stream char n)
       (declare (ignore char n))
       (let ((list (read stream nil (values) t)))
         `(make-real-matrix ',list)))))

#m((1.0)) returns an 1x1-matrix with entry 1.0.  Now it would sometimes be
practical to be able to say

  (let ((x 1)) `#m((,x)))

Unfortunately, I have not succeeded to modify my code such that this works.

Thank you for any information.

Nicolas

From: Kaz Kylheku
Subject: Re: `#2a((1.0))
Date: 
Message-ID: <cf333042.0405261054.7c9839b1@posting.google.com>
Nicolas Neuss <·······@iwr.uni-heidelberg.de> wrote in message news:<··············@ortler.iwr.uni-heidelberg.de>...
> Hello,
> 
> Using CMUCL:
> 
> 1. (let ((x 1)) `#(,x))  => #(1)

This is correct ANSI CL. Unquotes are allowed within #() vector
literals.

> 2. The following does not yield #2a((1)) but 
> 
> (let ((x 1)) `#2a((,x)))  => #2A((((LISP::|,|) . X)))

This is not correct ANSI CL, but undefined behavior. Unquotes are not
required to work within #A arrays (not even one-dimensional ones).
Unquoting is also not required to work in other things that resemble
lists, such as #S(...) structs or #C(...) complex numbers.

> (CLISP gives an error here)

This is deliberately so. The #A reader interacts with the backquote
reader to provide a diagnostic. If that were not done, then the result
would be something like

  #2A(((SYSTEM::UNQUOTE X)))

An array object with questionable contents would sneak into the
program.

> Questions: Is the code in (1) or (2) legal?  Should (2) work?
> 
> My actual problem is the following: I have written a reader macro #m for
> reading in matrices as follows

This is a different problem. I don't know whether unquotes are
required to work within your own custom syntax if it produces a list
object. In theory, if your object is read using a recursive read, it
ought to recognize that it's recursing within a backquote to which any
unquotes belong.

I can get this to work fine in CLISP.

>   (set-dispatch-macro-character
>    #\# #\m 
>    #'(lambda (stream char n)
>        (declare (ignore char n))
>        (let ((list (read stream nil (values) t)))
>          `(make-real-matrix ',list)))))

Note that the (values) above just means NIL in that context.

> #m((1.0)) returns an 1x1-matrix with entry 1.0.  Now it would sometimes be
> practical to be able to say
> 
>   (let ((x 1)) `#m((,x)))
> 
> Unfortunately, I have not succeeded to modify my code such that this works.

Assuming that the unquoting works through #m, you have another problem
here, which is that this expression yields the *form*
(MAKE-REAL-MATRIX ...) rather than its value!

The #m(...) syntax you have implemented does not actually produce a
matrix object at read time, but rather a constructor expression for a
matrix object which must be later evaluated to make that object. When
#m(...) occurs in an evaluation context, like when you type it into
your REPL, it *looks* as if it's producing a matrix literal at read
time, but it isn't. This becomes apparent when you quote it (or
backquote it).

Instead of the backquote, try just the regular quote: '#m((1.0)) and
compare it to '#(1 2). The former will not give you a 1x1 matrix, but
rather the constructor itself: (MAKE-REAL-MATRIX ...). The second
example will give you #(1 2), because the #() syntax decimates to a
vector object at read time, and that object is what is quoted, not
some constructor expression.

You can't fix this in any obvious way. If you stick an EVAL into your
reader macro, the evaluator will be confused by the little poops
produced by unquote within the constructor form.

The backquote implementation has to be aware of and integrated with
any syntax in order to unquote into objects produced by that syntax.

For example, the way the CLISP backquote handles vectors is that it
actually allows the vector object to be produced. It is handled later
when the backquote macro is expanded. When that macro sees that a
vector object is enclosed in it, it will rip that vector apart. If the
vector contains any unquotes, then it is transformed into a
constructor expression.  Thus,

   `#(1 ,b)

reads as the form:

   (SYSTEM::BACKQUOTE #(1 (SYSTEM::UNQUOTE B)))

The pretty-printer knows how to print this syntax as `#(1 ,b) so you
never see these symbols explicitly. Anyway, when this backquote is
evaluated, it rips apart the #(1 ...) vector object and processes the
unquote syntax within it, so it becomes something like:

   (VECTOR '1 B)

this becomes the replacement form for the macro which is evaluated in
its place.

Now suppose that the #() reader produced (VECTOR ...) expressions
instead of vector objects, and suppose that the CLISP backquote macro
was not aware of vectors at all. Then `#(1 ,b) would mean
(SYSTEM::BACKQUOTE (VECTOR '1 (SYSTEM::UNQUOTE B))), in other words
exactly the same as `(vector 1 ,b). This would expand to (LIST 'VECTOR
'1 B): replacement code which isn't the constructor expression for the
vector, but rather produces the constructor expression.
From: Nicolas Neuss
Subject: Re: `#2a((1.0))
Date: 
Message-ID: <87lljei5cz.fsf@ortler.iwr.uni-heidelberg.de>
···@ashi.footprints.net (Kaz Kylheku) writes:

> [very good and detailed information]

Thanks for your post.  I think I'll leave the #m-syntax for matrices
containing literal objects (and especially, I'll create them at read time).

Yours, Nicolas.
From: Adam Warner
Subject: Re: `#2a((1.0))
Date: 
Message-ID: <pan.2004.05.26.03.58.48.65237@consulting.net.nz>
Hi Nicolas Neuss,

> Hello,
> 
> Using CMUCL:
> 
> 1. (let ((x 1)) `#(,x))  => #(1)
> 
> 2. The following does not yield #2a((1)) but 
> 
> (let ((x 1)) `#2a((,x)))  => #2A((((LISP::|,|) . X)))
> 
> (CLISP gives an error here)
> 
> Questions: Is the code in (1) or (2) legal?  Should (2) work?
> 
> My actual problem is the following: I have written a reader macro #m for
> reading in matrices as follows
> 
>   (set-dispatch-macro-character
>    #\# #\m 
>    #'(lambda (stream char n)
>        (declare (ignore char n))
>        (let ((list (read stream nil (values) t)))
>          `(make-real-matrix ',list)))))
> 
> #m((1.0)) returns an 1x1-matrix with entry 1.0.  Now it would sometimes be
> practical to be able to say
> 
>   (let ((x 1)) `#m((,x)))
> 
> Unfortunately, I have not succeeded to modify my code such that this works.

(let ((x 1.0)) `#m((,x))) returns (make-real-matrix '((1.0)))

You shouldn't be (back)quoting the MAKE-REAL-MATRIX function. You have
inhibited its evaluation!

  (set-dispatch-macro-character
   #\# #\m 
   #'(lambda (stream char n)
       (declare (ignore char n))
       (let ((list (read stream nil (values) t)))
         (make-real-matrix list)))))

Now your code will work.

Regards,
Adam
From: Nicolas Neuss
Subject: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <87fz9nk17j.fsf_-_@ortler.iwr.uni-heidelberg.de>
Adam Warner <······@consulting.net.nz> writes:

>   (set-dispatch-macro-character
>    #\# #\m 
>    #'(lambda (stream char n)
>        (declare (ignore char n))
>        (let ((list (read stream nil (values) t)))
>          (make-real-matrix list)))))
> 
> Now your code will work.
> 
> Regards,
> Adam

Unfortunately, no:

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
(defun dummy-make-real-matrix (list)
  (coerce list 'vector))

(set-dispatch-macro-character
 #\# #\m 
 #'(lambda (stream char n)
     (declare (ignore char n))
     (let ((list (read stream nil (values) t)))
       (dummy-make-real-matrix list))))

* #m(1.0)
#M(1.0)

* (let ((x 1.0)) `#m(,x))

; In: LET ((X 1.0))

;   (LET (#)
;     #(#))
; Note: Variable X defined but never used.
; 
#(((LISP::|,|) . X))

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

I fear that this thing cannot be obtained that easily.  I would really like
to understand what #() is doing here and if it is portable behavior.  I
have taken a look at the function SHARP-LEFT-PAREN in
cmucl;src;code;sharpm.lisp, and it looks very non-portable (operating with
*backquote-count*, etc).

Yours, Nicolas.

P.S.: The subject line would better be: (let ((x 1.0)) `#(,x))
From: Barry Margolin
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <barmar-72472C.08265326052004@comcast.dca.giganews.com>
In article <·················@ortler.iwr.uni-heidelberg.de>,
 Nicolas Neuss <·······@iwr.uni-heidelberg.de> wrote:

> I fear that this thing cannot be obtained that easily.  I would really like
> to understand what #() is doing here and if it is portable behavior.  I
> have taken a look at the function SHARP-LEFT-PAREN in
> cmucl;src;code;sharpm.lisp, and it looks very non-portable (operating with
> *backquote-count*, etc).

Backquote has to work very closely with the readers for the various data 
structures that allow comma inside them, because it has to expand into 
appropriate type-specific function calls.  No standard mechanism is 
provided to customize this for user-defined reader macros.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Erann Gat
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <gNOSPAMat-6B55CE.08554726052004@nntp1.jpl.nasa.gov>
In article <·················@ortler.iwr.uni-heidelberg.de>,
 Nicolas Neuss <·······@iwr.uni-heidelberg.de> wrote:

> Adam Warner <······@consulting.net.nz> writes:
> 
> >   (set-dispatch-macro-character
> >    #\# #\m 
> >    #'(lambda (stream char n)
> >        (declare (ignore char n))
> >        (let ((list (read stream nil (values) t)))
> >          (make-real-matrix list)))))
> > 
> > Now your code will work.
> > 
> > Regards,
> > Adam
> 
> Unfortunately, no:
> 
> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
> (defun dummy-make-real-matrix (list)
>   (coerce list 'vector))
> 
> (set-dispatch-macro-character
>  #\# #\m 
>  #'(lambda (stream char n)
>      (declare (ignore char n))
>      (let ((list (read stream nil (values) t)))
>        (dummy-make-real-matrix list))))
> 
> * #m(1.0)
> #M(1.0)
> 
> * (let ((x 1.0)) `#m(,x))
> 
> ; In: LET ((X 1.0))
> 
> ;   (LET (#)
> ;     #(#))
> ; Note: Variable X defined but never used.
> ; 
> #(((LISP::|,|) . X))
> 
> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
> 
> I fear that this thing cannot be obtained that easily.  I would really like
> to understand what #() is doing here and if it is portable behavior.  I
> have taken a look at the function SHARP-LEFT-PAREN in
> cmucl;src;code;sharpm.lisp, and it looks very non-portable (operating with
> *backquote-count*, etc).
> 
> Yours, Nicolas.
> 
> P.S.: The subject line would better be: (let ((x 1.0)) `#(,x))

It works in MCL:

? (defun dummy-make-real-matrix (list)
  (coerce list 'vector))

DUMMY-MAKE-REAL-MATRIX
? (set-dispatch-macro-character
 #\# #\m 
 #'(lambda (stream char n)
     (declare (ignore char n))
     (let ((list (read stream nil (values) t)))
       (dummy-make-real-matrix list))))
T
? (let ((x 1)) `#m(,x))
#(1)
? 

E.
From: Kaz Kylheku
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <cf333042.0405270838.40ea3d7c@posting.google.com>
Erann Gat <·········@flownet.com> wrote in message news:<·······························@nntp1.jpl.nasa.gov>...
> It works in MCL:
> 
> ? (defun dummy-make-real-matrix (list)
>   (coerce list 'vector))
> 
> DUMMY-MAKE-REAL-MATRIX
> ? (set-dispatch-macro-character
>  #\# #\m 
>  #'(lambda (stream char n)
>      (declare (ignore char n))
>      (let ((list (read stream nil (values) t)))
>        (dummy-make-real-matrix list))))
> T
> ? (let ((x 1)) `#m(,x))
> #(1)
> ? 

My hypothesis is that it works more or less by fluke. Your reader
macro returns a simple vector. The backquote reader then thinks that
it's a vector that was produced by the #() reader. Consequently, it
handles the unquotes within that vector, exactly as if you had typed
`#(,x) rather than `#m(,x).

However, a backquote implementation is only required to handle
unquoting within vectors produced by the #() notation, not just any
old vectors.
From: Erann Gat
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <gNOSPAMat-11FA24.10125127052004@nntp1.jpl.nasa.gov>
In article <····························@posting.google.com>,
 ···@ashi.footprints.net (Kaz Kylheku) wrote:

> Erann Gat <·········@flownet.com> wrote in message 
> news:<·······························@nntp1.jpl.nasa.gov>...
> > It works in MCL:
> > 
> > ? (defun dummy-make-real-matrix (list)
> >   (coerce list 'vector))
> > 
> > DUMMY-MAKE-REAL-MATRIX
> > ? (set-dispatch-macro-character
> >  #\# #\m 
> >  #'(lambda (stream char n)
> >      (declare (ignore char n))
> >      (let ((list (read stream nil (values) t)))
> >        (dummy-make-real-matrix list))))
> > T
> > ? (let ((x 1)) `#m(,x))
> > #(1)
> > ? 
> 
> My hypothesis is that it works more or less by fluke. Your reader
> macro returns a simple vector. The backquote reader then thinks that
> it's a vector that was produced by the #() reader. Consequently, it
> handles the unquotes within that vector, exactly as if you had typed
> `#(,x) rather than `#m(,x).
> 
> However, a backquote implementation is only required to handle
> unquoting within vectors produced by the #() notation, not just any
> old vectors.

Then I'd call it an "extension" rather than a "fluke".

E.
From: Drew McDermott
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <c9ifbb$igi$1@news.wss.yale.edu>
 >> [Erann Gat]
 >>
 >>>It works in MCL:
 >>>
 >>>? (defun dummy-make-real-matrix (list)
 >>>  (coerce list 'vector))
 >>>
 >>>DUMMY-MAKE-REAL-MATRIX
 >>>? (set-dispatch-macro-character
 >>> #\# #\m
 >>> #'(lambda (stream char n)
 >>>     (declare (ignore char n))
 >>>     (let ((list (read stream nil (values) t)))
 >>>       (dummy-make-real-matrix list))))
 >>>T
 >>>? (let ((x 1)) `#m(,x))
 >>>#(1)
 >>>?
 >>
 >  [Kaz Kylheku]
 >>My hypothesis is that it works more or less by fluke. Your reader
 >>macro returns a simple vector. The backquote reader then thinks that
 >>it's a vector that was produced by the #() reader. Consequently, it
 >>handles the unquotes within that vector, exactly as if you had typed
 >>`#(,x) rather than `#m(,x).

I think the fluke is as folows: Some implementations of backquote are
implemented at read time, so that there is never an internal
representation of the backquoted expression.  Others just create a
special syntax as the result of a read, which is then macro-expanded.
The lack of a standard internal representation of a backquoted
expression is, in my opinion, a blemish on Lisp.  But in this case the
read-time implementations happen to give us an interesting extension
of backquote to arbitrary readable expressions, not just list
structures.  Macro-based implementations are forced to walk through an
expression making substitutions for (the internal representations of)
commafied subexpressions.  If they aren't written so as to walk
through an array, those expressions stay commafied.

 >>However, a backquote implementation is only required to handle
 >>unquoting within vectors produced by the #() notation, not just any
 >>old vectors.

Note that for a macro-based implementation this is an impossible
distinction to make.  It's like trying to distinguish between lists
that were read and lists that were consed by the program.

    -- Drew McDermott
From: Kaz Kylheku
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <cf333042.0406021242.7ac36db6@posting.google.com>
Drew McDermott <··················@at.yale.dot.edu> wrote in message news:<············@news.wss.yale.edu>...
> >> [Erann Gat]
>  >>
>  >>>It works in MCL:
>  >>>
>  >>>? (defun dummy-make-real-matrix (list)
>  >>>  (coerce list 'vector))
>  >>>
>  >>>DUMMY-MAKE-REAL-MATRIX
>  >>>? (set-dispatch-macro-character
>  >>> #\# #\m
>  >>> #'(lambda (stream char n)
>  >>>     (declare (ignore char n))
>  >>>     (let ((list (read stream nil (values) t)))
>  >>>       (dummy-make-real-matrix list))))
>  >>>T
>  >>>? (let ((x 1)) `#m(,x))
>  >>>#(1)
>  >>>?
>  >>
>  [Kaz Kylheku]
>  >>My hypothesis is that it works more or less by fluke. Your reader
>  >>macro returns a simple vector. The backquote reader then thinks that
>  >>it's a vector that was produced by the #() reader. Consequently, it
>  >>handles the unquotes within that vector, exactly as if you had typed
>  >>`#(,x) rather than `#m(,x).
> 
> I think the fluke is as folows: Some implementations of backquote are
> implemented at read time, so that there is never an internal
> representation of the backquoted expression.  Others just create a
> special syntax as the result of a read, which is then macro-expanded.
> The lack of a standard internal representation of a backquoted
> expression is, in my opinion, a blemish on Lisp.  But in this case the
> read-time implementations happen to give us an interesting extension
> of backquote to arbitrary readable expressions, not just list
> structures.  Macro-based implementations are forced to walk through an
> expression making substitutions for (the internal representations of)
> commafied subexpressions.  If they aren't written so as to walk
> through an array, those expressions stay commafied.

Read-time backquote implementations don't really have any substantial
advantage in bringing about such extensions. The reason for that is
that the evaluation of the material to be inserted into the template
cannot happen at read time. If an unquote occurs, say, within an
array, the reader has to know that it's dealing with an array, and
consequently that an array constructor expression has to be generated
in the place of the array object. If the unquotes occur in an
arbitrary read syntax, the read-time expander is faced with the same
problem as the macro-time expander: some object has been produced, and
it contains unquote bits. How to get to them? How to transform the
object into a constructor which makes an object of that type and
structure, containing the unquoted expressions to be properly
evaluated?

The only way that a read-time expander could do it completely blindly
is if it retained the raw character representation of the expression,
and arranged for it to be re-processed from scratch at evaluation
time, as a text-processing step: hunt down the commas, substitute the
printed representation of the values they represent in the given
evaluation context, and then pass the resulting string through the
reader. Ugh!

In other words, the backquote would work something like this:

 `#2A((,x ,y))

reads as the expression:

 (read-from-string (format nil "#2A((~s ~s))" x y))

Tee hee! It's sad that this is how things get done in some programming
languages. Code is prepared as a string and then passed through a
character-based eval.
From: Nicolas Neuss
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <874qq3jx3j.fsf@ortler.iwr.uni-heidelberg.de>
Nicolas Neuss <·······@iwr.uni-heidelberg.de> writes:

> * #m(1.0)
> #M(1.0)

The result should be #(1.0), of course.  I pasted from a wrong place.

Nicolas.
From: Adam Warner
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <pan.2004.05.26.12.28.53.955625@consulting.net.nz>
Hi Nicolas Neuss,

> I fear that this thing cannot be obtained that easily.  I would really
> like to understand what #() is doing here and if it is portable
> behavior.  I have taken a look at the function SHARP-LEFT-PAREN in
> cmucl;src;code;sharpm.lisp, and it looks very non-portable (operating
> with *backquote-count*, etc).

I understand the issue better now. Reader macros operate at the syntactic
level. It's only after they do their work that you end up with Lisp
objects to manipulate as atoms and *perhaps* s-expressions.

I've thought of two examples that make this clear. The first is a
non-dispatching reader macro and the second is a dispatching reader macro:

(let ((x 1)) "Hello,x World")

(let ((x 1)) #| Hello,x World |#)

If a reader macro doesn't return an s-expression it can't be manipulated
as one.

Regards,
Adam
From: Adam Warner
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <pan.2004.05.26.13.17.54.999972@consulting.net.nz>
I wrote:

> If a reader macro doesn't return an s-expression it can't be manipulated
> as one.

Fair enough. So let's build an s-expression for evaluation:

(defun \[-macro-character (stream char)
  (declare (ignore char))
  (cons 'dummy-vector (read-delimited-list #\] stream t)))

(defmacro dummy-vector (&rest args)
  `(coerce ',args 'vector))

(set-macro-character #\[ #'\[-macro-character)
(set-macro-character #\] (get-macro-character #\)))


The [ reader macro returns an s-expression. We can see this by quoting
the square bracketed "array":

'[1 2 3] => (dummy-vector 1 2 3)
 [1 2 3] => #(1 2 3)

As it's an s-expression we can use backquote as per usual:

`(let ((x 1)) [,x 2 3]) => (dummy-vector 1 2 3)

(defmacro example (a b c)
  `[,a ,(* 2 b) ,(* 3 c)])

(example 1 2 3) => #(1 4 9)

Hope this helps,
Adam
From: Lars Brinkhoff
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <85wu2zp8nq.fsf@junk.nocrew.org>
Adam Warner <······@consulting.net.nz> writes:
> (defmacro example (a b c)
>   `[,a ,(* 2 b) ,(* 3 c)])
> 
> (example 1 2 3) => #(1 4 9)
> 
> Hope this helps,

As long as it's understood that this is only an example of how to
reinvent the backquote syntax for vectors.

  (defmacro example (a b c)
    `#(,a ,(* 2 b) ,(* 3 c)))

  (example 1 2 3) => #(1 4 9)

See CLHS 2.4.6:

  `#(x1 x2 x3 ... xn) may be interpreted to mean
  (apply #'vector `(x1 x2 x3 ... xn))

-- 
Lars Brinkhoff,         Services for Unix, Linux, GCC, HTTP
Brinkhoff Consulting    http://www.brinkhoff.se/
From: Nicolas Neuss
Subject: Re: (let ((x 1.0)) `#(,x)) [Re: `#2a((1.0))]
Date: 
Message-ID: <87y8nfi5z2.fsf@ortler.iwr.uni-heidelberg.de>
Lars Brinkhoff <·········@nocrew.org> writes:

> See CLHS 2.4.6:
> 
>   `#(x1 x2 x3 ... xn) may be interpreted to mean
>   (apply #'vector `(x1 x2 x3 ... xn))

OK, thanks for this pointer.  So the behavior I want is indeed defined in
the standard for #(), but it is not available for #2a(()), and there is no
standard mechanism to get such a behavior for my #M()-reader macro.[1]

Thank you all,

Nicolas.

[1] At least, it is not easy.  Matlisp does implement a [ ... ] reader
macro which can handle also things like

(let ((x 1.0))
  [0.0 x])

But it is rather long...