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