我可以将 lambda 与即时 lambda 列表(没有宏)一起使用吗?
Can I use lambda with an on-the-fly lambda list (without macros)?
我正在尝试为 return 函数创建一个函数,其中包含动态生成的任意 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"
这正是我想要的行为。它 return 是一个函数,其 lambda 列表是动态提供的(在本例中,(fuel device)
。)是宏。但是,我在尝试将任意 lambda 列表 glom 到 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
应该 是一个宏 - 这样它会产生
current compilation environment 中的闭包。
但是,该函数将在 global environment.
中产生一个闭包
首先,您的宏过于复杂,如果您事先知道将使用多少参数,则无需发出应用调用并构建中间参数列表。这是另一个版本:
(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
的指定方式,如果实际参数的数量与预期参数的数量不同,您将不会收到警告。如果给定的参数太少,您将在运行时遇到错误,如果给定的参数太多,则将未使用的参数列表作为 return 值(也可以检查该列表以给出错误)。
(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
使用 ordinary lambda lists.
我正在尝试为 return 函数创建一个函数,其中包含动态生成的任意 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"
这正是我想要的行为。它 return 是一个函数,其 lambda 列表是动态提供的(在本例中,(fuel device)
。)是宏。但是,我在尝试将任意 lambda 列表 glom 到 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
应该 是一个宏 - 这样它会产生
current compilation environment 中的闭包。
但是,该函数将在 global environment.
首先,您的宏过于复杂,如果您事先知道将使用多少参数,则无需发出应用调用并构建中间参数列表。这是另一个版本:
(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
的指定方式,如果实际参数的数量与预期参数的数量不同,您将不会收到警告。如果给定的参数太少,您将在运行时遇到错误,如果给定的参数太多,则将未使用的参数列表作为 return 值(也可以检查该列表以给出错误)。
(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
使用 ordinary lambda lists.