
[英]Error: Lambda list with dots are only allowed in macros, not here : LIST?
[英]Can I use lambda with an on-the-fly lambda list (without macros)?
我正在尝试创建一个函数来返回函数,其中包含动态生成的任意lambda列表。 我可以用宏来做,但我试图去宏 - 如果我已经得到了:
(defmacro make-canned-format-macro (template field-names)
`(function (lambda ,field-names
(apply #'format `(nil ,,template ,,@field-names)))))
我可以用它如下:
* (make-canned-format-macro "~A-powered ~A" (fuel device))
#<FUNCTION (LAMBDA (FUEL DEVICE)) {10067D975B}>
* (setf (fdefinition 'zoom-zoom) (make-canned-format-macro "~A-powered ~A" (fuel device)))
#<FUNCTION (LAMBDA (FUEL DEVICE)) {1006835A5B}>
* (zoom-zoom "nuclear" "pogo stick")
"nuclear-powered pogo stick"
这正是我想要的行为。 它返回一个函数,其lambda列表是动态提供的(在这种情况下, (fuel device)
。)我正在尝试执行Proper Lisp Refactoring Thing并取消不必是宏的宏。 但是,我试图将一个任意的lambda列表变成一个正在函数中执行的lambda
:
* (defun make-canned-format (template field-names)
#'(lambda field-names (apply #'format `(nil ,template ,@field-names))))
; in: DEFUN MAKE-CANNED-FORMAT
; #'(LAMBDA FIELD-NAMES (APPLY #'FORMAT `(NIL ,TEMPLATE ,@FIELD-NAMES)))
;
; caught ERROR:
; The lambda expression has a missing or non-list lambda list:
; (LAMBDA FIELD-NAMES (APPLY #'FORMAT `(NIL ,TEMPLATE ,@FIELD-NAMES)))
; (SB-INT:NAMED-LAMBDA MAKE-CANNED-FORMAT
; (TEMPLATE FIELD-NAMES)
; (BLOCK MAKE-CANNED-FORMAT
; #'(LAMBDA FIELD-NAMES (APPLY #'FORMAT `(NIL ,TEMPLATE ,@FIELD-NAMES)))))
;
; caught STYLE-WARNING:
; The variable TEMPLATE is defined but never used.
;
; caught STYLE-WARNING:
; The variable FIELD-NAMES is defined but never used.
;
; compilation unit finished
; caught 1 ERROR condition
; caught 2 STYLE-WARNING conditions
MAKE-CANNED-FORMAT
我正在努力做甚么可能吗? (除了一些可怕的eval
hack,它的可读性低于宏,我的意思是。)
要打开make-canned-format
到一个函数,你需要更换function
与compile
或(coerce (lambda ...) 'function)
。
但是,您的重构是错误的。 make-canned-format
应该是一个宏 - 这样它将在当前的编译环境中产生一个闭包。 但是,该函数将在全局环境中产生闭包。
首先,你的宏过于复杂,如果你事先知道将使用多少个参数,你不需要发出一个调用来应用和构建一个中间参数列表。 这是另一个版本:
(defmacro lambda-format ((&rest args) template)
`(lambda ,args (format nil ,template ,@args)))
您可以通过使用可变参数函数和APPLY
去除宏,但这意味着通过仅检查生成的函数(使用例如inspect或describe),您无法预先知道需要多少参数:
(defun curry-format (template)
(lambda (&rest args)
(apply #'format nil template args)))
在格式化的情况下,您可以使用FORMATTER
宏,它能够解析模板格式并在运行时为其提供参数之前发出警告:
(defmacro template ((&rest args) template)
(let ((format-fn (gensym))
(template-fn (copy-symbol :template)))
`(let ((,format-fn (formatter ,template)))
(flet ((,template-fn ,args (funcall ,format-fn nil ,@args)))
(function ,template-fn)))))
这里我使用FLET,以便生成的函数具有用户友好的名称,但您也可以使用lambda。
(template (a b) "~x ~b")
#<FUNCTION (FLET "TEMPLATE") {1002B93D0B}>
如果你在上面调用describe,你可能会看到签名是准确的:
Lambda-list: (A B)
可变参数不是这种情况。
宏需要一个文字字符串,并且可以在宏展开期间检查它是否包含有效格式:
(template (a b) "~x ~!")
;; error in FORMAT: Unknown directive (character: EXCLAMATION_MARK)
;; ~x ~!
给定如何指定FORMATTER
,如果实际参数的数量与预期参数的数量不同,则不会发出警告。 如果给定的参数太少,则在运行时会出现错误,如果给定的参数太多,则会将未使用的参数列表作为返回值(该列表也可以检查以给出错误)。
(defun make-canned-format (template field-names)
#'(lambda field-names (apply #'format `(nil ,template ,@field-names))))
这是不可能的。 在lambda表达式中,参数列表是一个列表,而不是随后评估的任意符号。 Common Lisp需要一个固定的参数列表 - 而不是变量。 此评估表未评估:
(lambda (a b c) ; (a b c) this is a list of parameters.
; This list is not evaluated.
...)
(lambda foo ; foo is not allowed syntax. Common Lisp expects a list.
...)
LAMBDA
使用普通的lambda列表 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.