首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我是否可以使用lambda和一个正在运行的lambda列表(没有宏)?

我是否可以使用lambda和一个正在运行的lambda列表(没有宏)?
EN

Stack Overflow用户
提问于 2018-09-14 20:03:27
回答 3查看 287关注 0票数 2

我正在尝试创建一个函数来返回函数,其中包含任意的lambda列表,它是动态生成的。我可以用宏来做这件事,但是我正在尝试去宏化我已经拥有的东西:

代码语言:javascript
复制
(defmacro make-canned-format-macro (template field-names)
  `(function (lambda ,field-names
               (apply #'format `(nil ,,template ,,@field-names)))))

我可以如下所用:

代码语言:javascript
复制
* (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中:

代码语言:javascript
复制
* (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攻击之外,它的可读性要比宏低得多。)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-09-14 20:44:43

要将make-canned-format转换为函数,需要将function替换为compile(coerce (lambda ...) 'function)

然而,您的重构是错误的。make-canned-format应该是一个宏-这样它将在环境中产生一个闭包。然而,该函数将在环境中生成一个闭包。

票数 4
EN

Stack Overflow用户

发布于 2018-09-14 21:20:57

首先,宏过于复杂,如果预先知道将使用多少参数,则不需要发出应用和构建中间参数列表的调用。以下是另一个版本:

代码语言:javascript
复制
(defmacro lambda-format ((&rest args) template)
  `(lambda ,args (format nil ,template ,@args)))

您可以通过使用变量函数和APPLY来消除宏,但这意味着只检查生成的函数(使用检查或描述),您无法预先知道需要多少参数:

代码语言:javascript
复制
(defun curry-format (template)
  (lambda (&rest args)
    (apply #'format nil template args)))

在格式方面,您可以使用FORMATTER宏,它能够在运行时给出参数之前解析模板格式并发出警告:

代码语言:javascript
复制
(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。

代码语言:javascript
复制
(template (a b) "~x ~b")
#<FUNCTION (FLET "TEMPLATE") {1002B93D0B}>

如果您调用它上的描述,您可能会看到签名是精确的:

代码语言:javascript
复制
Lambda-list: (A B)

变量变体的情况并非如此。

宏需要一个文字字符串,并可以在宏展开期间检查它包含的有效格式:

代码语言:javascript
复制
(template (a b) "~x ~!")
 ;; error in FORMAT: Unknown directive (character: EXCLAMATION_MARK)
 ;;  ~x ~!

考虑到指定FORMATTER的方式,如果实际参数的数量与预期参数的数量不同,则不会发出警告。如果给定的参数太少,则在运行时会有一个错误,如果有太多的给定参数,则会有一个未使用的参数列表作为返回值(可以检查该列表是否也会出现错误)。

票数 4
EN

Stack Overflow用户

发布于 2018-09-15 07:13:07

代码语言:javascript
复制
(defun make-canned-format (template field-names)
   #'(lambda field-names (apply #'format `(nil ,template ,@field-names))))

这是不可能的在lambda表达式中,参数列表是一个列表,而不是它随后计算的任意符号。通用Lisp需要一个固定的参数列表,而不是一个变量。未对此列表进行评估:

代码语言:javascript
复制
(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使用普通羔羊名单

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52338570

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档