我可以通过它的值在函数名称空间中定义一个函数吗?

时间:2016-03-22 03:34:55

标签: common-lisp

我最近开始学习CL,我试图找出是否可以在函数名称空间中为符号设置值。

我想根据功能组合来定义函数,或者只是通过现有函数来定义函数(例如,我只需要在玩具“Hello,World!”级项目中重写identity两次。我不确定它是否可能,因为它可能会破坏命名空间分离(至少没有强制执行)。我还尝试macroexpand defun实际做了什么;作为一个初学者,它对我来说太神秘了,但它似乎是内置的核心部分(我正在使用SBCL)。

所以,例如而不是说:

(defun myfn (x) x)

我只想说:

(def..? myfn identity)

如果我不能这样做,我怎么能避免这类代码重复? (包括由函数组合创建的函数,而不仅仅是创建同义词)。

1 个答案:

答案 0 :(得分:5)

当前环境中可能存在绑定到符号的函数:

(setf (symbol-function 'myfn) #'identity)

还有(setf FDEFINTION)大致相同,但也支持setf个功能。

对于词法绑定函数(FLETLABELS),我们无法做到这一点。

示例如何使用(setf fdefinition)

设置符号功能
CL-USER 11 > (setf (fdefinition 'myfn) #'identity)
#<Function IDENTITY 410003F974>

CL-USER 12 > (myfn 10)
10

进一步评论

请注意,它在当前环境中执行此操作。因此

(defun myfn (x) x)

可能被

之类的东西取代
(eval-when (:compile-toplevel :load-toplevel :execute)
  (setf (fdefinition 'myfn) #'identity))

Tha优势:在编译过程中,该功能将一如既往。

要记住的一件事:

符号对象可能带有一些信息。例如原始函数名称,如果有的话:

CL-USER 13 > #'identity
#<Function IDENTITY 410003F974>

设置符号的功能单元格不会改变:

CL-USER 14 > #'myfn
#<Function IDENTITY 410003F974>

它与原始内部名称相同的功能对象。一个人可能能够访问该名称,但无法改变它:

CL-USER 18 > (nth-value 2 (function-lambda-expression #'identity))
IDENTITY

自递归函数也存在问题:

CL-USER 19 > (defun foo (n)
               (if (zerop n)
                   1
                 (* n (foo (1- n)))))  ; here foo calls the function foo
FOO

现在我们将BAR设置为使用函数FOO

CL-USER 20 > (setf (symbol-function 'bar) #'foo)
#<interpreted function FOO 4060004084>


CL-USER 21 > (bar 10)
3628800

我们在此重新定义FOO

CL-USER 22 > (defun foo (n)
               (if (zerop n)
                   1
                 (+ n (foo (1- n)))))
FOO

BAR仍然使用旧的FOO,可能会也可能不会调用新的FOO

CL-USER 23 > (bar 10)
460

OOPS!我们更改了FOO,但它对BAR有奇怪的效果:第一次迭代是旧的FOO,下一次递归调用是新的FOO。

BARFOO是同一功能的两个不同版本。但是两者都调用函数FOO,它可能是旧函数或新函数 - 取决于你如何解释或编译代码。

CL-USER 24 > #'foo
#<interpreted function FOO 40600041F4>

CL-USER 25 > #'bar
#<interpreted function FOO 4060004084>