Macros 使用宏构建具有动态输入的函数
我的目标是拥有一个宏,该宏使用在别处生成的参数列表自动构建函数。我希望宏返回一个由函数和它使用的参数列表(符号列表)组成的列表。我用的是SBCL 生成参数列表 假设参数列表由以下内容生成:Macros 使用宏构建具有动态输入的函数,macros,arguments,common-lisp,Macros,Arguments,Common Lisp,我的目标是拥有一个宏,该宏使用在别处生成的参数列表自动构建函数。我希望宏返回一个由函数和它使用的参数列表(符号列表)组成的列表。我用的是SBCL 生成参数列表 假设参数列表由以下内容生成: (defun input-syms () (list 'in1 'in2 'in3)) ;;=> (IN1 IN2 IN3) 使用此参数列表构建函数 根据中的有用答案,我使用了类似的标签(添加列表元素,只是为了示例): 这似乎有效,尽管我认为可能有一种更简单的方法(list,@input list
(defun input-syms ()
(list 'in1 'in2 'in3))
;;=> (IN1 IN2 IN3)
使用此参数列表构建函数
根据中的有用答案,我使用了类似的标签(添加列表元素,只是为了示例):
这似乎有效,尽管我认为可能有一种更简单的方法(list,@input list)
似乎没有必要,但将其替换为,input list
不起作用
随函数一起返回参数列表
这就是我困惑的地方,它似乎与输入列表的确切含义有关。我认为这与我们正在操纵符号有关,所以我尝试将symbol value
放入其中,但没有效果
我想获得的,以非工作代码表示的是:
(defmacro create-funtest2 ()
(let ((input-list (input-syms)))
`(labels ((fun-created ,input-list
(reduce #'+ (list ,@input-list))))
(list #'fun-created ,input-list))))
它必须返回:(#(IN1 IN2 IN3))
。
但是调用create-funtest2
会产生编译错误变量IN2未绑定。
。我想它是在评估这个符号,而不是给我这个符号
我需要能够获得用于构建函数的符号,我在调用函数时使用它们来知道哪个输入是什么。这个符号列表也可以被create funtest
宏修改,所以我真的需要从宏内部获取它
编辑1
谢谢雷纳·乔斯维格的回答。困扰我的事情实际上是将符号列表作为符号返回。我猜create-funtest2
的扩展代码(来自您给出的扩展)应该如下所示:
(LABELS ((FUN-CREATED (IN1 IN2 IN3)
(REDUCE #'+ (LIST IN1 IN2 IN3))))
(LIST #'FUN-CREATED (LIST 'IN1 'IN2 'IN3)))
因此宏的输出是(#(IN1 IN2 IN3))
。
问题是,我想计算输入列表
,但将其元素保留为符号(不确定是否正确,抱歉)
编辑2
谢谢你。create-funtest2
的工作版本为:
(defmacro create-funtest2 ()
(let ((input-list (test-input-syms)))
`(labels ((fun-created ,input-list
(reduce #'+ (list ,@input-list))))
(list #'fun-created (quote ,input-list)))))
这提供了扩展(感谢Rainer提供的代码片段):
并按以下方式调用:
(defparameter *fun-created2* (create-funtest2))
(funcall (car *fun-created2*) 1 2 3) ; => 6, OK
(second *fun-created2*) ; => (IN1 IN2 IN3), OK
输入列表是(IN1 IN2 IN3)
这项工作:
(reduce #'+ (list IN1 IN2 IN3))
这不起作用:
(reduce #'+ (IN1 IN2 IN3))
原因:1中没有函数
我是你的朋友:
CL-USER 58 > (let ((*print-circle* t)
(*PRINT-RIGHT-MARGIN* 50))
(pprint (copy-tree (macroexpand-1 '(create-funtest2)))))
(LABELS ((FUN-CREATED (IN1 IN2 IN3)
(REDUCE #'+ (LIST IN1 IN2 IN3))))
(LIST #'FUN-CREATED (IN1 IN2 IN3)))
扩展代码有两个问题:
最后一行中的函数IN1
不存在
最后一行中的变量IN2
和IN3
不存在
也许宏扩展将帮助您解决问题
要获得更多帮助,您需要稍微更好地解释您想做什么。更简单的版本
当给定任意长的输入列表时,您可能希望使用reduce
的原因是函数调用受到限制。但是,在这里,您将使用符号列表作为函数参数,这受到限制。此外,第二个必须大于或等于第一个。因此,如果符号列表足够短,可以用作参数列表,那么它也足够短,可以用作+
调用中的参数
(defun input-symbols ()
'(in1 in2 in3))
(defmacro create-funtest ()
(let ((args (input-symbols)))
`(lambda ,args (+ ,@args))))
在上面,我还使用了一个匿名函数,但这并不重要
返回用于评估的符号
您的第二个版本(使用与上述相同的方法重写)是:
(defmacro bad-create-funtest2 ()
(let ((args (input-symbols)))
`(list (lambda ,args (+ ,@args))
,args)))
你对此有何评论
(macroexpand '(bad-create-funtest2))
=> (LIST (LAMBDA (IN1 IN2 IN3) (+ IN1 IN2 IN3))
(IN1 IN2 IN3))
在这里,您可以看到您正试图使用参数in2
和in3
调用in1
。
您不想对符号列表求值,只需传递未求值的符号即可
(macroexpand '(create-funtest2))
=> (LIST (LAMBDA (IN1 IN2 IN3) (+ IN1 IN2 IN3))
'(IN1 IN2 IN3))
返回未计算的符号
通过引用该值,可以确保不会计算该值
(macroexpand '(create-funtest2))
=> (LIST (LAMBDA (IN1 IN2 IN3) (+ IN1 IN2 IN3))
'(IN1 IN2 IN3))
就这样!关于减少的观点,这只是为了举例。有点傻,但我所需要的只是(引用,args)。我将使用工作版本的create-funtest2
编辑我的问题。我发现“(list,@input list)似乎没有必要,但用just代替它,input list不起作用”。我在深水区发现一名潜水同伴。:)我清楚地记得这条学习曲线,所以很好地掌握正在发生的事情是很好的,因为编写宏所需的一项基本技能是在编写前一个代码的同时,保持扩展代码与其扩展之间的差异。简言之,仅使用“(reduce'+,inputs)”就可以“生成”(reduce'+(in1in2in3)),完全不是您想要的。Meta tip:macroexpand-1Indeed,我通过查看扩展了解到了这一点。我的一些最大的惊喜来自于简单地在扩展代码中打印出值(因此我在调用macroexpansion时可以看到它们的输出)。
(defmacro create-funtest2 ()
(let ((args (input-symbols)))
`(list (lambda ,args (+ ,@args))
(quote ,args))))
(macroexpand '(create-funtest2))
=> (LIST (LAMBDA (IN1 IN2 IN3) (+ IN1 IN2 IN3))
'(IN1 IN2 IN3))