【问题标题】:Can I define a function in the function namespace by it's value? [duplicate]我可以通过它的值在函数命名空间中定义一个函数吗? [复制]
【发布时间】:2016-03-22 03:34:54
【问题描述】:

我最近开始学习 CL,我想弄清楚是否可以为函数命名空间中的符号设置值。

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

例如而不是说:

(defun myfn (x) x)

我宁愿说:

(def..? myfn identity)

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

【问题讨论】:

  • 只是一个想法,您可以添加一个扩展为(defun myfun (&rest args) (apply identity args)) 的宏。当然,在 Lisp-1 中,您可以只使用 (define myfn identity)
  • 请务必查看从副本链接的一些功能。周围有很多有用的信息。标题为why defun is not the same as (setq )? 的文章有一些很好的讨论。
  • 另外,为了清楚起见,您可以使用#' 表示法获取符号的函数值。即,你不需要做(let ((id (lambda (x) x))) (compose id ...))。你可以只做(let ((id #'identity)) (compose id ...))(compose #'identity ...)

标签: common-lisp


【解决方案1】:

这对于绑定到符号的函数来说是可能的,在当前环境中:

(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))

这个优点:在编译过程中函数会像往常一样被知道。

要记住的一件事:

符号对象可能携带一些信息。比如原来的函数名,如果有的话:

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

哎呀!我们更改了 FOO,但它对 BAR 产生了奇怪的影响:第一次迭代是旧的 FOO,下一次递归调用是新的 FOO。

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

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

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

【讨论】:

    猜你喜欢
    • 2012-02-27
    • 2016-11-23
    • 2018-09-06
    • 1970-01-01
    • 2012-01-20
    • 1970-01-01
    • 2011-09-18
    • 2021-02-05
    • 2012-09-20
    相关资源
    最近更新 更多