【问题标题】:Why this lisp recursive macro doesn't work?为什么这个 lisp 递归宏不起作用?
【发布时间】:2013-11-02 04:41:21
【问题描述】:

我在 guile 中有宏 let--(比如 let* 使用 lambdas):

(define (let-make-lambdas pairs body)
    (if (null? pairs)
        `((lambda () ,@body))
        `((lambda (,(caar pairs))
            ,(let-make-lambdas (cdr pairs) body))
          ,(cadar pairs))))

(define-macro (let-- pairs . body)
    (let-make-lambdas pairs body))

当我使用外部函数进行代码生成时它工作正常,但下面的代码(只是一个宏)不起作用:

(define-macro (let-- pairs . body)
    (if (null? pairs)
        `((lambda () ,@body))
        `((lambda (,(caar pairs))
            ,(let-- (cdr pairs) body))
          ,(cadar pairs))))

为什么?

【问题讨论】:

  • 忘记括号了? :P
  • 宏调用似乎与其定义不符:点不见了。
  • @sds . 用于定义 Common Lisp 中的 &rest 列表。在第一种情况下,jcubic 定义了一个函数来执行代码扩展,并且 macro does 包括 .
  • @JoshuaTaylor:我的意思是宏的调用必须有一个.(如我的回答)或一个@(如你的)
  • @sds 哦,我明白你的意思了。 (let-- ...) 在定义中可能是(let-- (cdr pairs) . body)。对(只要解决了其他问题)。对不起,我误会了。

标签: macros lambda lisp scheme guile


【解决方案1】:

我认为 Joshua 找到了您问题的答案。我只想指出Scheme 标准使用syntax-rules 和syntax-case。 syntax-rules 可能是这样的:

;; make let* with lambdas
(define-syntax let--
  (syntax-rules ()
    ;; base case, last pair
    ((let-- ((key1 value1)) . body) 
     ((lambda (key1) . body ) value1))

    ;; default case, several
    ((let-- ((key1 value1) . kv-pairs) . body) 
     ((lambda (key1) (let-- kv-pairs . body)) value1))))

(let-- ((a 'a) (b a) (c b)) (list a b c)) ; ==> (a a a)

【讨论】:

  • 我更喜欢支持它们的 lisp 宏和方案实现,但仍然感谢您的回答。
【解决方案2】:

第二个,你不想

,(let-- (cdr pairs) body)

而是

(let-- ,(cdr pairs) ,@body)

也就是说,你的直接宏实现应该是

(define-macro (let-- pairs . body)
    (if (null? pairs)
        `((lambda () ,@body))
        `((lambda (,(caar pairs))
            (let-- ,(cdr pairs) ,@body))
          ,(cadar pairs))))

您不想在宏扩展时评估内部(let-- ...);它是应该生成的源的一部分。 (当然,它会在不久之后被宏扩展。)为了突出这一点,考虑一个宏

(plus a b c d)

进入

(+ a (+ b (+ c d)))

它需要像这样扩展

(+ ,(car args) (plus ,@(cdr args)))

但不是

(+ ,(car args) ,(plus (cdr args)))

因为后者会尝试评估(plus '(b c d)),这是行不通的。

【讨论】:

    【解决方案3】:

    这是一个有效的 Common Lisp 版本:

    (defmacro let1-- (pairs . body)
      (if (null pairs)
          `((lambda () ,@body))
          `((lambda (,(caar pairs))
             (let-- ,(cdr pairs) . ,body))
             ,(cadar pairs))))
    > (macroexpand '(let1-- ((a 1) (b 2)) (+ b a)))
    ((LAMBDA (A) (LET-- ((B 2)) (+ B A))) 1) ;
    T
    > (let1-- ((a 1) (b 2)) (+ b a))
    3
    

    我猜对应的Scheme版本是,

    (define-macro (let-- pairs . body)
        (if (null? pairs)
            `((lambda () ,@body))
            `((lambda (,(caar pairs))
                (let-- ,(cdr pairs) . ,body))
              ,(cadar pairs))))
    

    【讨论】:

      猜你喜欢
      • 2021-10-28
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2021-10-22
      • 1970-01-01
      • 2017-11-29
      • 1970-01-01
      • 2022-11-12
      相关资源
      最近更新 更多