我正在尝试使用CLISP实现eval
函数。
我的动机:假设我有一个像这样的Lisp程序:
(defun call (arg)
(cond
(some-condition (call (other (strange (functions (on arg)))))
(t nil)
)
)
(defun mysterious-function (arg)
(call (strange (functions (on arg))))
)
(mysterious-function 100) ; only this line can be changed
我想知道(mysterious-function 100)
中实际调用的是什么。
目前我的想法如下,但障碍是:
- 如何查找符号(当前使用
eval
( - 如何获取函数的定义(例如,获取类似
(defun f (x))
的内容(,然后对其进行解析 - 如何检测宏并展开它们
我的方向正确吗?
(defun my-eval (body)
(cond
((typep body 'integer) body)
((typep body 'float) body)
((typep body 'rational) body)
((typep body 'complex) body)
((typep body 'boolean) body)
((typep body 'symbol) (eval body))
((typep body 'list) (eval body))
(t (error))
)
)
(my-eval '(mysterious-function 100))
代码中的大多数情况都可以用一个检查来替换:((constantp body) body)
至于其他情况:
- 您可以使用
boundp
来检查符号是否具有全局值 - 要查找全局符号值,可以使用
symbol-value
fboundp
可用于检查符号是否全局绑定到函数- 要查找全局函数,可以使用
symbol-function
访问其函数对象,有时还可以使用function-lambda-expression
从函数对象中检索可解析的源代码列表。有时这将不起作用,因为CLISP函数可以在C中定义 - 要检查符号是否有关联的全局宏,请使用
macro-function
(如果有,则返回非零( - 要展开宏窗体,请使用
macroexpand
您可能还需要使用special-operator-p
检测特殊运算符,并对其进行相应的处理。
我认为,如果你尽可能地将你解释的代码限制为宏和用户定义的函数,你试图做的事情就会简化。我记得读过一篇关于遗传编程中使用的快速eval函数的文章,该函数跳过了评估代码的宏扩展阶段,它的方法看起来与您所想的类似。