Lambda 使匿名函数易于识别

Lambda 使匿名函数易于识别,lambda,common-lisp,Lambda,Common Lisp,我想向一类匿名函数添加一些元数据,使它们易于识别。到目前为止,我所有的想法都是粗俗或可疑的: plist项可以工作,但显然它只用于符号,而不是lambda 我可以在文档字符串中插入一些内容: (lambda (x) "is-special" ... 但这看起来真的很难看,或者: (lambda (x) (if (eq x 'special) t ... 更加丑陋 在函数对象上设置属性是否有一种不那么粗俗的方法 我还可以使用类型系统来区分我的功能: (defmacro

我想向一类匿名函数添加一些元数据,使它们易于识别。到目前为止,我所有的想法都是粗俗或可疑的:

plist项可以工作,但显然它只用于符号,而不是lambda

我可以在文档字符串中插入一些内容:

(lambda (x) "is-special" ...
但这看起来真的很难看,或者:

(lambda (x)
  (if 
   (eq x 'special) 
   t
   ...
更加丑陋

在函数对象上设置属性是否有一种不那么粗俗的方法

我还可以使用类型系统来区分我的功能:

(defmacro nlambda (name (&rest lambda-list) &body body)
  `(labels ((,name (,@lambda-list)
              ,@body))
     #',name))
将函数放置在结构或CLOS对象中是可能的,但感觉很麻烦

是否可以创建作为函数类型的自定义子类型的lambda


CLOS对象可以用作可执行函数吗?我正在考虑类似于python的call属性的东西。

我还不知道足够的MOP来回答你最后的问题,但我可以建议你一种简单的方法来做你想做的事情

您可以声明一个特殊变量来跟踪添加了元数据的lambda:
(defvar*带注释的lambdas*(生成哈希表))

然后定义一个函数,从中获取/设置lambda

(defun get-lambda (lambda &optional (annotated-lambdas *annotated-lambdas*))
  (gethash lambda annotated-lambdas))

(defun (setf get-lambda) (annotation lambda &optional (annotated-lambdas *annotated-lambdas*))
  (setf (gethash lambda annotated-lambdas) annotation))
现在您已经可以测试一些东西了:

(let ((l (lambda (x) (1+ x))))
  (setf (get-lambda l) "Add one."))
此时,
*带注释的lambdas*
应该已经包含一个元素

现在,您可以使用一个小宏来简化此操作:

(defmacro lambda* ((&rest args) (annotation &optional (annotated-lambdas *annotated-lambdas*)) &body body)
  (let ((name (gensym)))
`(let ((,name (lambda (,@args)
        ,@body)))
   (setf (get-lambda ,name ,annotated-lambdas) ,annotation))))
您可以这样使用:

(lambda* (x) ("Add one.")
  (+1 x))
当然,要访问注释,您需要访问lambda,我假设您需要访问lambda,因为否则您将使用函数(它只是一个指向lambda的符号)。
此外,“注释”可以是任何内容,字符串、列表、列表、plist,甚至是哈希表。

如果是用于打印,我会这样做:

CL-USER 8 > (flet ((foo (a b) (+ a b))) #'foo)
#<interpreted function FOO 40600008E4>

CL-USER 9 > (defmacro nlambda (name &rest rest)
              `(flet ((,name ,@rest))
                 (function ,name)))
NLAMBDA

CL-USER 10 > (mapcar (lambda (x) (nlambda foo (y) (+ x y))) '(1 2 3 4))
(#<interpreted function FOO 4060000B54>
 #<interpreted function FOO 4060000B84>
 #<interpreted function FOO 4060000BB4>
 #<interpreted function FOO 4060000BE4>)

有关另一种方法,请参见:.

编辑:如果您的实现打印
flet
标签
函数的名称,请参见快速脏选项:

(defmacro nlambda (name (&rest lambda-list) &body body)
  `(labels ((,name (,@lambda-list)
              ,@body))
     #',name))
如果需要可靠地打印函数名,请继续阅读


上一个问题后面的一个示例,假设您的公共Lisp实现遵循元对象协议(MOP):

请注意,必须根据您的实现替换
mop
包名,或者如果您使用cl-mop


编辑:这里有一些你可以使用它的方法

直接:

(make-instance 'funcallable-object
  :name 'foo
  :function #'(lambda (<args>)
                <body>))
(使实例成为可调用的对象
:name'foo
:函数#’(λ()
))
使用宏:

(defmacro nlambda (name (&rest lambda-list) &body body)
  `(labels ((,name (,@lambda-list)
              ,@body))
     (make-instance 'funcallable-object
       :name ',name
       :function #',name)))

(nlambda foo (<args>)
  <body>)
(defmacro nlambda(名称和剩余lambda列表)和body)
`(标签(,名称(,@lambda列表)
(@body))
(使“实例”成为可调用对象
:name',name
:函数#',名称)
(nlambda foo)
)

我在示例中使用了
标签
,而不是
flet
,因为我相信命名lambda的更大用途是它的递归能力。

我刚刚发现了可能就是您正在寻找的库。可通过quicklisp获取该文件。

右侧。通常使用非标准的弱哈希表。通过这种方式,未引用的函数可以得到gcd…@RainerJoswig您能详细说明一下吗,这听起来很有趣。@Sharpie,实现对弱哈希表(例如,,,和)有非标准的支持,以允许对条目进行GC'ed。无法通过编程获得该名称,是吗?那会很好的。关于你的最后一个问题,在一个有MOP(元对象协议)的实现上,你可以使用和专门化。
(defmacro nlambda (name (&rest lambda-list) &body body)
  `(labels ((,name (,@lambda-list)
              ,@body))
     (make-instance 'funcallable-object
       :name ',name
       :function #',name)))

(nlambda foo (<args>)
  <body>)