Pau*_*ulM 7 lambda input common-lisp
我希望能够从键盘读取lambda表达式。例如,如果功能方块已经被拒绝,我可以输入符号名称:
(defun square (x) (* x x))
Run Code Online (Sandbox Code Playgroud)
以便在评估以下内容时:
(funcall (read) 2)
Run Code Online (Sandbox Code Playgroud)
用户可以输入square,结果为4。但是如果用户输入
(lambda (x) (* x x))
Run Code Online (Sandbox Code Playgroud)
结果是一个错误,例如在Macintosh Common Lisp中,
错误:(LAMBDA(X)(* XX))无法执行或应用
有没有一种简单的方法可以做到这一点,而我却错过了?
谢谢。
read返回list,必须先评估 a ,然后才能对其进行funcall编辑。
这可以使用读取时间评估来完成:
(funcall (read) 2)
#.(lambda (x) (* x x))
==> 4
Run Code Online (Sandbox Code Playgroud)
但是,通常来说,这是一个安全漏洞(您正在评估用户提供的代码-如果键入)#.(start-nuclear-war)?因此,谨慎的工程师在读取无法控制的输入时将绑定*read-eval*到该位置nil。
因此,最好coerce显式使用:
(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
Run Code Online (Sandbox Code Playgroud)
由于您使用read,通常您需要评估返回的表格以获得有意义的值。但在特定情况下,您可以使用COERCE。例如,从REPL:
CL-USER> (coerce '+ 'function)
#<FUNCTION +>
Run Code Online (Sandbox Code Playgroud)
上述的发现,以该符号的功能+是fbound。
CL-USER> (coerce '(lambda (x) (* x x)) 'function)
#<FUNCTION (LAMBDA (X)) {53F2BF2B}>
Run Code Online (Sandbox Code Playgroud)
上面的代码使用了一个lambda表达式并将其变成一个函数对象。
CL-USER 8 > (defun read-function (&optional (stream *standard-input*))
(let ((f (read stream)))
(cond (; function object
(functionp f) f)
(; symbol naming a function
(symbolp f) (symbol-function f))
(; (function f)
(and (consp f)
(eq (first f) 'function))
(eval f))
(; (lambda ...)
(and (consp f)
(eq (first f) 'lambda))
(eval f)))))
READ-FUNCTION
Run Code Online (Sandbox Code Playgroud)
例子:
CL-USER 9 > (read-function)
#.#'+
#<Function + 40F0044AD4>
CL-USER 10 > (read-function)
+
#<Function + 40F0044AD4>
CL-USER 11 > (read-function)
#'+
#<Function + 40F0044AD4>
CL-USER 12 > (read-function)
(lambda (a b) (+ a b))
#<anonymous interpreted function 4060000C8C>
Run Code Online (Sandbox Code Playgroud)