I've been playing with Lisp a bit to get a hang of the basics. In one
app I have a list of assorted items, some of which are functions that
may need to get called later. But I'm missing something in my syntax
to make it work. I've reduced the question to:
CL-USER> (funcall #'(lambda () (format t "called~%")))
called
NIL
Ok, and
CL-USER> (nth 1 '("foo" #'(lambda () (format t "called~%"))))
#'(LAMBDA () (FORMAT T "called~%"))
But combining these,
CL-USER> (funcall (nth 1 '("foo" #'(lambda () (format t "called~%")))))
; Evaluation aborted
looks like it doesn't "see" the function as a function, confirmed by
CL-USER> (functionp (nth 1 '("foo" #'(lambda () (format t "called~%")))))
NIL
Why? And how to fix it?
Thanks..
--
Jyri J. Virkki - Santa Cruz, CA
Jyri J. Virkki wrote:
> I've been playing with Lisp a bit to get a hang of the basics.
You skipped the basic known as QUOTE, aka '
That is not your fault. All introductory material messes noobs up by
always using things like '(a b c) in their elementary examples. So noobs
think that is how to make a list. Yeah, if you want everything quoted.
Which is line only for most elementary examples. :)
Try: (funcall (nth 0 (list (lambda () (print "hi mom")))))
ken
> In one
> app I have a list of assorted items, some of which are functions that
> may need to get called later. But I'm missing something in my syntax
> to make it work. I've reduced the question to:
>
> CL-USER> (funcall #'(lambda () (format t "called~%")))
> called
> NIL
>
> Ok, and
>
> CL-USER> (nth 1 '("foo" #'(lambda () (format t "called~%"))))
> #'(LAMBDA () (FORMAT T "called~%"))
>
> But combining these,
>
> CL-USER> (funcall (nth 1 '("foo" #'(lambda () (format t "called~%")))))
> ; Evaluation aborted
>
> looks like it doesn't "see" the function as a function, confirmed by
>
> CL-USER> (functionp (nth 1 '("foo" #'(lambda () (format t "called~%")))))
> NIL
>
> Why? And how to fix it?
>
>
> Thanks..
>
--
Cells: http://common-lisp.net/project/cells/
"And I will know my song well before I start singing." - Bob Dylan
·······@localhost.localdomain (Jyri J. Virkki) writes:
> I've been playing with Lisp a bit to get a hang of the basics. In one
> app I have a list of assorted items, some of which are functions that
> may need to get called later. But I'm missing something in my syntax
> to make it work. I've reduced the question to:
>
> CL-USER> (funcall #'(lambda () (format t "called~%")))
> called
> NIL
>
> Ok, and
>
> CL-USER> (nth 1 '("foo" #'(lambda () (format t "called~%"))))
> #'(LAMBDA () (FORMAT T "called~%"))
>
> But combining these,
>
> CL-USER> (funcall (nth 1 '("foo" #'(lambda () (format t "called~%")))))
> ; Evaluation aborted
>
> looks like it doesn't "see" the function as a function, confirmed by
>
> CL-USER> (functionp (nth 1 '("foo" #'(lambda () (format t "called~%")))))
> NIL
>
> Why? And how to fix it?
First, you should note that 'x is just a shorthand for (quote x)
and #'x is just a shorthand for (function x)
there's nothing special about them.
Next, you should know that most Common Lisp implementations lie to you:
[3]> (print '(function x))
#'X
#'X
[4]> (asdf-load :com.informatimago.common-lisp)
[...]
[5]> (com.informatimago.common-lisp.cons-to-ascii:print-conses '(function x))
(FUNCTION . (X . ()))
#'X
Compare with:
[6]> (print '(fonction x))
(FONCTION X)
(FONCTION X)
[7]> (com.informatimago.common-lisp.cons-to-ascii:print-conses '(fonction x))
(FONCTION . (X . ()))
(FONCTION X)
[8]>
As you can see, a mere list, no different from any other list, instead
of being printed as its elements inside parentheses like any other
list, is printed as #'x just because its first element is CL:FUNCTION
and it contains only two element. I find this special casing
unjustifiable, but I'm no lisp implementer (yet).
Now, check out your second result. It prints as :
#'(LAMBDA () (FORMAT T "called~%"))
and if you read it back, it would be read as a function.
But it isn't a function! It's a plain list:
[8]> (com.informatimago.common-lisp.cons-to-ascii:print-conses
(nth 1 '("foo" #'(lambda () (format t "called~%")))))
(FUNCTION . ((LAMBDA . (() . ((FORMAT . (T . (called~% . ()))) . ()))) . ()))
#'(LAMBDA NIL (FORMAT T "called~%"))
[9]> (car (nth 1 '("foo" #'(lambda () (format t "called~%")))))
FUNCTION
[10]> (type-of (nth 1 '("foo" #'(lambda () (format t "called~%")))))
CONS
[11]>
The reason why, may be clearer if you avoided ' and #' and wrote QUOTE
and FUNCTION instead:
(nth 1 (QUOTE ("foo" (FUNCTION (lambda () (format t "called~%"))))))
What does this conspicuous QUOTE do here?
Yes, it prevents the evaluation of its argument and returns it as is.
Therefore you get the second element of the list:
("foo" (FUNCTION (lambda () (format t "called~%"))))
which is itself the list:
(FUNCTION (lambda () (format t "called~%")))
There's no function here!
Note that functions cannot be read. When you print a function, it's
printed with #< which is a reader dispatching macro for unreadable
stuff:
[11]> (print (function sin))
#<SYSTEM-FUNCTION SIN>
#<SYSTEM-FUNCTION SIN>
[12]> (print (lambda (x y) (+ (* 2 x) y)))
#<FUNCTION :LAMBDA (X Y) (+ (* 2 X) Y)>
#<FUNCTION :LAMBDA (X Y) (+ (* 2 X) Y)>
[13]> #<FUNCTION :LAMBDA (X Y) (+ (* 2 X) Y)>
*** - READ from
#<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM>
#<IO TERMINAL-STREAM>>
: objects printed as #<...> cannot be read back in
Therefore, to input a function you need to actually _evaluate_ an
expression that will find or build it.
(FUNCTION SIN) is such an expression.
When evaluated, it finds the function named SIN and returns it.
(FUNCTION (lambda () (format t "called~%"))) is another such expression.
When evaluated, it builds an anonymous function that formats "called~%"
and returns it.
(LAMBDA () (format t "called~%")) is such an expression too!
Indeed, when this form is evaluated, since LAMBDA is a macro that
expands (lambda args . body) to (function (lambda args . body)),
it results in another anonymous function all the same.
So what you need to get functions is have the expressions that build
or find them be evaluated. Therefore you must avoid QUOTE. You can
use LIST to build lists, after evaluating the elements:
[15]> (list (quote "foo") (lambda () (format t "called~%")) (function sin))
("foo" #<FUNCTION :LAMBDA NIL (FORMAT T "called~%")> #<SYSTEM-FUNCTION SIN>)
[16]> (funcall (second (list (quote "foo") (lambda () (format t "called~%")) (function sin))))
called
NIL
Another way to build such a list, when it contains a lot of data that
shouldn't be evaluated and a few that should:
(list (quote a) (quote b) (quote 1) (function car) (quote 3) (quote "hi"))
is to use the backquote and comma reader macros:
`(a b 1 ,(function car) 3 "hi")
reading this backquote expression, the reader builds an expressions
that will give a result simular to the list expression above.
[20]> (funcall (second `("foo" ,(lambda () (format t "called~%")) ,(function sin))))
called
NIL
[Unfortunately, there is no standard expansion for backquote and
comma. Well their purpose is to have a short and convenient notation
to write these lists, so nobody would write:
(backquote a b 1 (comma (function car)) 3 "hI")
anyways.]
[You may have been surprised by my (quote "foo") above ;-) There's a
difference between "foo" and (quote "foo"), but when you evaluate
them, you have in the first case a self-evaluating atom, where
evaluating "foo" results in "foo" itself, and in the second case,
QUOTE returns its argument "foo" unevaluated, as is, "foo" itself.
The result of evaluating (quote "foo") or "foo" is the same! (But
when things are not evaluated, then (quote "foo") is a list while
"foo" is a string, not the same).]
--
__Pascal Bourguignon__ http://www.informatimago.com/
In deep sleep hear sound,
Cat vomit hairball somewhere.
Will find in morning.
+ Pascal Bourguignon <······@informatimago.com>:
| First, you should note that 'x is just a shorthand for (quote x)
| and #'x is just a shorthand for (function x)
| there's nothing special about them.
You mean, apart from them being special forms? ;->
(Yeah, I know what you're saying - if they don't even get to be
evaulated, they're just plain lists ...)
--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
when there is no ground whatsoever for supposing it is true.
-- Bertrand Russell
On Fri, 24 Mar 2006, Jyri J. Virkki wrote:
> CL-USER> (nth 1 '("foo" #'(lambda () (format t "called~%"))))
> #'(LAMBDA () (FORMAT T "called~%"))
Here, you make a sensible attempt to understand the problem, but you
are fooled by the printer, which uses the same shortcut notations that
are available for you in the reader. #'something is equivalent to
(function something).
> But combining these,
>
> CL-USER> (funcall (nth 1 '("foo" #'(lambda () (format t "called~%")))))
> ; Evaluation aborted
>
> looks like it doesn't "see" the function as a function, confirmed by
>
> CL-USER> (functionp (nth 1 '("foo" #'(lambda () (format t "called~%")))))
> NIL
>
> Why? And how to fix it?
Trying:
(type-of (nth 1 '("foo" #'(lambda () (format t "called~%")))))
might lead you to the right direction.
The problem is that the quote in '("foo" ... ) suppresses evaluation
of everything in ... . Therefore the form
(function (lambda () (format t "called~%")))
is not evaluated into the actual function, but remains just a sublist
in your list. In general you will want to use the function list to
construct lists, as opposed to the quote operator, which always
produces constant lists.
-Mikko
Frode Vatvedt Fjeld <······@cs.uit.no> writes:
> ·······@localhost.localdomain (Jyri J. Virkki) writes:
>
>> CL-USER> (funcall #'(lambda () (format t "called~%")))
>> CL-USER> (funcall (nth 1 '("foo" #'(lambda () (format t "called~%")))))
>> ; Evaluation aborted
>> Why?
>
> Try to replace funcall with print, and compare the results.
This is confusing because implementers choose to print the shortcut
in most cases.
--
__Pascal Bourguignon__ http://www.informatimago.com/
The world will now reboot. don't bother saving your artefacts.
Pascal Bourguignon <······@informatimago.com> writes:
> Frode Vatvedt Fjeld <······@cs.uit.no> writes:
>> ·······@localhost.localdomain (Jyri J. Virkki) writes:
>>
>>> CL-USER> (funcall #'(lambda () (format t "called~%")))
>>> CL-USER> (funcall (nth 1 '("foo" #'(lambda () (format t "called~%")))))
>>> ; Evaluation aborted
>>> Why?
>>
>> Try to replace funcall with print, and compare the results.
>
> This is confusing because implementers choose to print the shortcut
> in most cases.
It is not confusing, because one print command will print
#<FUNCTION (LAMBDA NIL)> ; or similar
and the other will print
#'(LAMBDA () (FORMAT T "called~%"))
which is sufficiently different that an alarm bell could ring.
I don't think that there would be any extra clarity in this case if
the second printed thing were
(FUNCTION (LAMBDA () (FORMAT T "called~%")))
Christophe