我正在尝试创建一个函数来返回函数,其中包含任意的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))。我正在尝试进行适当的Lisp重构,并消除不必是宏的宏。然而,我被困在试图将任意的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攻击之外,它的可读性要比宏低得多。)
发布于 2018-09-14 20:44:43
要将make-canned-format转换为函数,需要将function替换为compile或(coerce (lambda ...) 'function)。
然而,您的重构是错误的。make-canned-format应该是一个宏-这样它将在环境中产生一个闭包。然而,该函数将在环境中生成一个闭包。
发布于 2018-09-14 21:20:57
首先,宏过于复杂,如果预先知道将使用多少参数,则不需要发出应用和构建中间参数列表的调用。以下是另一个版本:
(defmacro lambda-format ((&rest args) template)
`(lambda ,args (format nil ,template ,@args)))您可以通过使用变量函数和APPLY来消除宏,但这意味着只检查生成的函数(使用检查或描述),您无法预先知道需要多少参数:
(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}>如果您调用它上的描述,您可能会看到签名是精确的:
Lambda-list: (A B)变量变体的情况并非如此。
宏需要一个文字字符串,并可以在宏展开期间检查它包含的有效格式:
(template (a b) "~x ~!")
;; error in FORMAT: Unknown directive (character: EXCLAMATION_MARK)
;; ~x ~!考虑到指定FORMATTER的方式,如果实际参数的数量与预期参数的数量不同,则不会发出警告。如果给定的参数太少,则在运行时会有一个错误,如果有太多的给定参数,则会有一个未使用的参数列表作为返回值(可以检查该列表是否也会出现错误)。
发布于 2018-09-15 07:13:07
(defun make-canned-format (template field-names)
#'(lambda field-names (apply #'format `(nil ,template ,@field-names))))这是不可能的在lambda表达式中,参数列表是一个列表,而不是它随后计算的任意符号。通用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使用普通羔羊名单。
https://stackoverflow.com/questions/52338570
复制相似问题