Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Sharpdot

26 views
Skip to first unread message

Tel A.

unread,
Jun 2, 2006, 3:03:56 PM6/2/06
to
Every now and then I've seen use of the sharpdot (#.) reader character.
I'm curious as to what it is.

Hyperspec says that sharpdot invokes "read-time evaluation". I have a
gist of what this means, but I can't think of a reason why you'd want
that to occur. Speculatively, I'd guess it might show up in a very
complex macro, but I really have no idea.

Thus, my questions: what exactly does #. do and why would you want to
use it?

Thanks.

Tel A.

unread,
Jun 2, 2006, 3:21:22 PM6/2/06
to

This might be addressed in an answer to the first question, but
experimentation with the read macro is producing very weird behavior...

CL-USER> (macroexpand-1 (quote (function +)))
#'+
NIL
CL-USER> (macroexpand-1 (quote #.(function +)))
#<Function + {1019A909}>
NIL
CL-USER> (macroexpand-1 (quote (function #.+)))
#'(MACROEXPAND-1 '#<Function + {1019A909}>)
NIL
CL-USER> (macroexpand-1 (quote (function #.+)))
#'(MACROEXPAND-1 '#'(MACROEXPAND-1 '#<Function + {1019A909}>))
NIL

This occurred in cmucl and clisp. Where am I making the giant error? ; )

Ken Tilton

unread,
Jun 2, 2006, 3:33:26 PM6/2/06
to

(defconstant tcl-ok 0)
(defconstant tcl-error 1)

(case (tcl-eval("hi mom")) ;; where tcl-eval returns 0 or 1
(#.tcl-ok ...)
(#.tcl-error ...))

CASE would not evaluate a plain tcl-ok, it would treat it as a symbol
which would not match 0 or 1.

That is one good example, methinks.

kenny

--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.

Jesus...@gmail.com

unread,
Jun 3, 2006, 2:30:31 AM6/3/06
to
Tel A. wrote:
> Thus, my questions: what exactly does #. do and why would you want to
> use it?

An expression preceded by #. evaluates the expression, and parses as if
the result of the #. expression were written in place of the #.
expression. For instance:

[1]> (setf foo '(+ 1 1))
[2]> foo
(+ 1 1)
[3]> 'foo
foo
[4]> #.foo
2
[5]> '#.foo
(+ 1 1)

Pascal Bourguignon

unread,
Jun 3, 2006, 4:56:20 AM6/3/06
to
Jesus...@gmail.com writes:

> Tel A. wrote:
>> Thus, my questions: what exactly does #. do and why would you want to
>> use it?
>
> An expression preceded by #. evaluates the expression, and parses as if
> the result of the #. expression were written in place of the #.
> expression. For instance:

No. It doesn't need to parse anything, since the expression after
#. already returns lisp objects!

> [1]> (setf foo '(+ 1 1))
> [2]> foo
> (+ 1 1)
> [3]> 'foo
> foo

> [5]> '#.foo
> (+ 1 1)

Here, the cons cell (+ . (1 1)) is not parsed either, because there's
no string "(+ 1 1)", no characters '(' '+' ' ' '1' ' ' '1' or ')' to
be parsed. The evaluation of foo returns this list, and the reader
inserts it as-in in the list it builds while reading '.

> [4]> #.foo
> 2

Here, the same occurs, but is not seen, the evaluation of foo returns
a list (actually, the first cons cell of this "list"), and the reader
returns it as-is. Then EVAL evaluates it and computes 2 which it
returns to the printer to be printed.

--
__Pascal Bourguignon__ http://www.informatimago.com/

HEALTH WARNING: Care should be taken when lifting this product,
since its mass, and thus its weight, is dependent on its velocity
relative to the user.

Rainer Joswig

unread,
Jun 3, 2006, 5:03:07 AM6/3/06
to
In article <1149275036....@y43g2000cwc.googlegroups.com>,
"Tel A." <abraha...@gmail.com> wrote:

This is a facility by the Lisp reader. It allows you to have
Lisp expressions evauated during read-time.

Example:

a string

"#.(* 10 pi)"

CL-USER 1 > (read-from-string "#.(* 10 pi)")
31.41592653589793D0

So it allows you to embed programs in text and these
programs will be executed by the reader.
Note that it also works for streams:

(with-input-from-string (in-stream "#.(* 10 pi)")
(read in-stream))

Similar it would work for reading from files and
network streams.

Note that you can switch of the evaluation.

CL-USER 4 > (let ((*read-suppress* t)) (read-from-string "#.(* 10 pi)"))
NIL
11


Okay, one typical use is to embed Lisp expressions in input.
Here is another one.

Since the typical Lisp system uses READ to read Lisp code,
it can be used also in programs.

Say you have some variable defined somewhere:
CL-USER 5 > (defparameter *m* 100)
*M*

You can write code like this:
(defun foo (n)
(* n #.(* *m* pi)))

For example the typical Lisp listener runs some kind
of glorified (LOOP (PRINT (EVAL (READ))))).

So there is a read stage:

CL-USER 7 > (read)
(defun foo (n)
(* n #.(* *m* pi)))
(DEFUN FOO (N) (* N 314.1592653589793D0))


Or in a simple expression

CL-USER 9 > (print (eval (print (read))))
(* 10 #.(* *m* pi))
(* 10 314.1592653589793D0)
3141.5926535897934D0
3141.5926535897934D0

Since you have the whole Common Lisp available at read
time, you can embed all kinds of complex computation
during read time.

Remember the REPL:

1) READ reads the program and generates a Lisp datastructure

you can use READTABLEs, READ Macros and Read-Time evaluation to
change this stage

2) Your code gets Macroexpanded. Macros transform the code
from above to other code.

You can use Macros at this stage.

3) EVAL. your code gets compiled. The compiled code runs.
Alternatively the code gets evaluated by an interpreter.

4) The results will be printed.

There are various ways to influence how results are printed.
One thing is to write methods for PRINT-OBJECT

5) The REPL starts at 1)

Add error-handling and much more...

--
http://lispm.dyndns.org/

rydis

unread,
Jun 3, 2006, 12:54:07 PM6/3/06
to

When you're evaluating + as a variable, as in the last two cases,
its value is that of the last form entered to the REPL.

',mr

--
[Emacs] is written in Lisp, which is the only computer language that is
beautiful. -- Neal Stephenson, _In the Beginning was the Command Line_

Tel A.

unread,
Jun 3, 2006, 2:08:10 PM6/3/06
to
Ok, I can see some places where it's useful now. I think especially
interesting is how it can be used to evaluate lisp values within
strings. I suppose the sharpsign reader macros have a greater
precendence than the minimal built-in syntax.

Thanks for the examples and explanations.

Pascal Bourguignon

unread,
Jun 3, 2006, 7:58:19 PM6/3/06
to
Rainer Joswig <jos...@lisp.de> writes:

> In article <1149275036....@y43g2000cwc.googlegroups.com>,
> "Tel A." <abraha...@gmail.com> wrote:
>
>> Every now and then I've seen use of the sharpdot (#.) reader character.
>> I'm curious as to what it is.
>>
>> Hyperspec says that sharpdot invokes "read-time evaluation". I have a
>> gist of what this means, but I can't think of a reason why you'd want
>> that to occur. Speculatively, I'd guess it might show up in a very
>> complex macro, but I really have no idea.
>>
>> Thus, my questions: what exactly does #. do and why would you want to
>> use it?
>>
>> Thanks.
>
> This is a facility by the Lisp reader. It allows you to have
> Lisp expressions evauated during read-time.

> [...]


> CL-USER 1 > (read-from-string "#.(* 10 pi)")
> 31.41592653589793D0
>
> So it allows you to embed programs in text and these
> programs will be executed by the reader.

Well, of course, it can be used in programs (as long as programs are
read), but it can also be used in user data, as long as it's
eventually read with READ.

(defparameter *default-config* '((:speed . 3) (:email . "nobody")))
(defvar *config*
(with-open-file (conf (merge-pathnames
(make-pathname :name "MYAPP" :type "CONF"
:case :common)
(user-homedir-pathname))
:if-does-not-exist nil)
(if conf
(read conf)
*default-config*)))

Then the user could have in his configuration file:
---(~/myapp.conf)-------------------------------------------------------

(
(:speed . #.(/ (* 10 1024 1024) 3600))
(:email . #.(concatenate 'string "pjb@"
(nth-value 1 (LINUX:|gethostname| #x7f000001))))
. #.*default-config*
)

------------------------------------------------------------------------


And we would get
*config* --> ((:SPEED . 131072/45) (:EMAIL . "pjb@thalassa") (:SPEED . 3)
(:EMAIL . "nobody"))

--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.

Thomas A. Russ

unread,
Jun 5, 2006, 2:39:54 PM6/5/06
to
"Tel A." <abraha...@gmail.com> writes:

> Thus, my questions: what exactly does #. do and why would you want to
> use it?

It evaluates expressions at read time.

It was at least sometimes used to provide computed values without the
need to rely on a compiler doing constant folding for you. One such
example would be

(defvar *seconds-per-day* #.(* 60 60 24))

which is perhaps clearer about how the value is derived than writing the
equivalent

(defvar *seconds-per-day* 86400)


--
Thomas A. Russ, USC/Information Sciences Institute

Pascal Bourguignon

unread,
Jun 5, 2006, 9:16:05 PM6/5/06
to
t...@sevak.isi.edu (Thomas A. Russ) writes:

> "Tel A." <abraha...@gmail.com> writes:
>
>> Thus, my questions: what exactly does #. do and why would you want to
>> use it?
>
> It evaluates expressions at read time.
>
> It was at least sometimes used to provide computed values without the
> need to rely on a compiler doing constant folding for you. One such
> example would be
>
> (defvar *seconds-per-day* #.(* 60 60 24))
>
> which is perhaps clearer about how the value is derived than writing the
> equivalent
>
> (defvar *seconds-per-day* 86400)

But you don't earn anything over:

(defvar *seconds-per-day* (* 60 60 24))

which evaluates the product at run-time.


A "better" example would be:

(defun #.(progn (format *query-io* "What the name of this function should be?")
(read *query-io*)) (args...)
...)


--
__Pascal Bourguignon__ http://www.informatimago.com/

"Debugging? Klingons do not debug! Our software does not coddle the
weak."

Kent M Pitman

unread,
Jun 5, 2006, 10:57:14 PM6/5/06
to
Pascal Bourguignon <p...@informatimago.com> writes:

> t...@sevak.isi.edu (Thomas A. Russ) writes:
>
> > (defvar *seconds-per-day* #.(* 60 60 24))
> >
> > which is perhaps clearer about how the value is derived than writing the
> > equivalent
> >
> > (defvar *seconds-per-day* 86400)
>
> But you don't earn anything over:
>
> (defvar *seconds-per-day* (* 60 60 24))
>
> which evaluates the product at run-time.

Actually, it's a tiny savings in this case but a moral victory to use
#. because you assure that the computation will be done in the
compiler and dumped to a compiled file as a constant rather than
having the expression to compute it be dumped into the fasl file
(taking up space) and loaded at load-time (taking up time repeatedly,
once for each load, rather than just once for compilation time for all
time ... and also assuming the compiler doesn't optimize it because it's
trivial--something you can't do in the general case).

> A "better" example would be:
>
> (defun #.(progn (format *query-io* "What the name of this function should be?")
> (read *query-io*)) (args...)
> ...)

Yes, this is probably a better example. I just wanted to note that this
one being better doesn't make the prior one something about which you don't
earn anything. :) In the general case, evaluation at readtime can still do
a long compilation earlier than the compiler would, or even in some cases
(because of the halting problem) earlier than the compiler would be able to.

0 new messages