Reading lambda expressions from keyboard in Common Lisp
read
returns a list
which has to be evaluated before it can be funcall
ed.
This can be accomplished using read-time evaluation:
(funcall (read) 2)
#.(lambda (x) (* x x))
==> 4
However, generally speaking, this is a security hole (you are evaluating user-supplied code - what if they typed #.(start-nuclear-war)
?) so a cautious engineer will bind *read-eval*
to nil
when reading input they have no control over.
Thus it is much better to use coerce
explicitly:
(funcall (coerce (let ((*read-eval* nil)) (read)) 'function) 2)
1+
==> 3
(funcall (coerce (let ((*read-eval* nil)) (read)) 'function) 2)
(lambda (x) (* x x))
==> 4
Since you are using read
, in general you would need to evaluate the returned forms to obtain meaningful values. But in your particular case, you can use COERCE
. For example, from a REPL:
CL-USER> (coerce '+ 'function)
#<FUNCTION +>
The above finds the function to which the symbol +
is fbound.
CL-USER> (coerce '(lambda (x) (* x x)) 'function)
#<FUNCTION (LAMBDA (X)) {53F2BF2B}>
The above takes a lambda expression and turn it into a function object.
You get that error because READ
returns just the list (LAMBDA (X) (* x x))
, it does not evaluate it to a function. To do that, you would need to write:
(funcall (eval (read)) 2)
Note though that in that case, just writing square
doesn't work anymore, the user would now need to enter #'square
.