我最近开始学习CL,我试图找出是否可以在函数名称空间中为符号设置值.
我想根据函数组合定义函数,或者只是通过现有函数定义函数(例如,我只需要identity在玩具"Hello,World!"级项目中重写两次).我不确定它是否可能,因为它可能会破坏命名空间分离(至少没有强制执行).我也尝试过实际做的macroexpand事情defun; 作为一个初学者,它对我来说太神秘了,但似乎内置的核心部分(我正在使用SBCL).
所以,例如,而不是说:
(defun myfn (x) x)
Run Code Online (Sandbox Code Playgroud)
我宁愿说:
(def..? myfn identity)
Run Code Online (Sandbox Code Playgroud)
如果我不能这样做,我怎么能避免这类代码重复?(包括由函数组合创建的函数,而不仅仅是创建同义词).
在当前环境中,对于符号绑定的函数是可能的:
(setf (symbol-function 'myfn) #'identity)
Run Code Online (Sandbox Code Playgroud)
还有(setf FDEFINTION)哪些大致相同,但也支持setf功能.
对于词法绑定函数(by FLET和LABELS),不能这样做.
示例如何使用设置符号函数 (setf fdefinition)
CL-USER 11 > (setf (fdefinition 'myfn) #'identity)
#<Function IDENTITY 410003F974>
CL-USER 12 > (myfn 10)
10
Run Code Online (Sandbox Code Playgroud)
进一步的评论
请注意,它在当前环境中执行此操作.从而
(defun myfn (x) x)
Run Code Online (Sandbox Code Playgroud)
可能会被类似的东西所取代
(eval-when (:compile-toplevel :load-toplevel :execute)
(setf (fdefinition 'myfn) #'identity))
Run Code Online (Sandbox Code Playgroud)
优点:在编译期间,该函数将通常被称为.
要记住的一件事:
符号对象可以携带一些信息.例如原始函数名称,如果有的话:
CL-USER 13 > #'identity
#<Function IDENTITY 410003F974>
Run Code Online (Sandbox Code Playgroud)
设置符号的功能单元格不会改变:
CL-USER 14 > #'myfn
#<Function IDENTITY 410003F974>
Run Code Online (Sandbox Code Playgroud)
它与原始内部名称是相同的函数对象.一个人可能能够访问该名称,但无法更改它:
CL-USER 18 > (nth-value 2 (function-lambda-expression #'identity))
IDENTITY
Run Code Online (Sandbox Code Playgroud)
自递归函数也存在问题:
CL-USER 19 > (defun foo (n)
(if (zerop n)
1
(* n (foo (1- n))))) ; here foo calls the function foo
FOO
Run Code Online (Sandbox Code Playgroud)
现在我们设置BAR使用该功能FOO
CL-USER 20 > (setf (symbol-function 'bar) #'foo)
#<interpreted function FOO 4060004084>
CL-USER 21 > (bar 10)
3628800
Run Code Online (Sandbox Code Playgroud)
在这里我们重新定义FOO:
CL-USER 22 > (defun foo (n)
(if (zerop n)
1
(+ n (foo (1- n)))))
FOO
Run Code Online (Sandbox Code Playgroud)
BAR仍然使用旧的FOO,可能会或可能不会调用新的FOO.
CL-USER 23 > (bar 10)
460
Run Code Online (Sandbox Code Playgroud)
OOPS!我们改变了FOO,但它对BAR有奇怪的影响:第一次迭代是旧的FOO,下一次递归调用是新的FOO.
BAR并且FOO是同一功能的两个不同版本.但是两者都调用函数FOO,可能是旧函数或新函数 - 取决于您如何解释或编译代码.
CL-USER 24 > #'foo
#<interpreted function FOO 40600041F4>
CL-USER 25 > #'bar
#<interpreted function FOO 4060004084>
Run Code Online (Sandbox Code Playgroud)