【问题标题】:Are incremental Macro definition possible?增量宏定义是否可能?
【发布时间】:2011-02-14 11:46:42
【问题描述】:

我经常发现以下类型的增量定义很有用:

(define (foo) (display "bar"))
(foo)
;prints bar
(define foo (let ((bar foo))
              (lambda ()
                (display "foo")
                (bar))))

(foo)
;prints foobar

如何使用宏执行这种类型的增量定义? 我无法让 let-syntax 提供相同的功能。

目前我使用 plt 方案,但也希望在不同的 lisp 实现中看到答案。

编辑:

天真地我想做以下事情:

(define-syntax foo
  (syntax-rules ()
    ((_) (display "bar"))))

(define-syntax foo
  (let-syntax ((old-foo (syntax-rules () ((_) (foo)))))
    (syntax-rules ()
      ((_) (begin
             (display "foo")
             (old-foo))))))

将原始宏转换为有效的 plt 方案宏:

(require-for-syntax scheme/base) 
(define-syntax foo
  (syntax-rules ()
    [(foo) (display "bar")]))
(define-syntax foo
  (let ([old (syntax-local-value #'foo)])
    (lambda (stx)
      #`(begin #,((syntax-rules ()
               [(_) (begin (display "foo"))]) stx)
             #,(old #'(_))))))
(foo)

如果我错过了更好的方法,请告诉我。

【问题讨论】:

    标签: lisp scheme macros


    【解决方案1】:

    我不认为你可以用宏做这样的事情。我也认为尝试没有任何意义。

    请注意,宏不仅仅是一些具有额外魔力的函数!宏完全不同。

    也许您正在寻找 Common Lisp 中的方法组合之类的东西?

    【讨论】:

    • 谢谢。您是否也没有看到功能案例的重点?还是 python 中的装饰器的情况?无处有用吗?或者为什么它特别对宏没有用?......现在我已经阅读了一些关于方法组合的内容,它们似乎提供了与 python 中的装饰器相同的功能。为什么这种抽象级别对函数有用,但对宏没有意义?
    • @Davorak:装饰器在功能上与方法组合不同。装饰器在定义时执行,而组合方法在方法被调用时执行。后者是面向方面编程的重要组成部分。如果有的话,装饰器更类似于宏,但在更有限的情况下使用。
    • 您似乎描述的是实现差异而不是功能差异。我可以使用装饰器在函数之前、之后或周围运行额外的代码,或者完全覆盖它。这就像我在阅读规范时所理解的方法组合一样,您可以使用方法组合在现有函数之前、之后或周围运行额外的代码。
    • 这样做确实没有多大意义,但是说宏不是函数是错误的——至少在 Lisp 和大多数 Schemes 中它们确实是。
    • Svante:不同之处在于围绕宏运行的机器——它们如何绑定、如何调用等等。
    【解决方案2】:

    使用宏执行此操作,您正在创建地球上最难维护的软件。

    编辑:在 Common Lisp 中是可能的。我不记得我曾在源代码中看到过它。

    向函数或宏添加行为在 Common Lisp 社区中通常称为“建议”或“建议”。一些“建议”工具也可以建议宏。

    【讨论】:

    • 目前,我使用方案编程的任何内容都与关键任务甚至我的个人工作流程无关。此外,我上面的增量定义很容易成为类似 python 的函数装饰器。所以我的问题的另一种措辞是宏装饰器可能吗?
    • @Davorak:你会装饰装饰器吗?
    • 在 python 中,装饰器可以用于装饰器的定义,而我还没有机会在我自己的代码中以这种方式使用它们,我确实看到这样做很有用。只是为了确保我之前的评论清楚我所说的宏装饰器是一个可以用来装饰另一个宏的宏。
    • @Rainer Joswig 谢谢你,我会在 CL 中寻找建议工具。
    • Davorak:python 中的装饰器与宏无关,它们类似于建议。
    【解决方案3】:

    FWIW(这绝对不多,因为这几乎是一种用脚练习目标的练习),下面是您在 PLT Scheme 中如何做到这一点,只使用卫生的syntax-rules 宏:

    (define-syntax foo
      (syntax-rules ()
        [(foo x) (list 'x '= x)]))
    (define-syntax foo
      (let ([old (syntax-local-value #'foo)])
        (compose (syntax-rules ()
                   [(_ x ...) (list 'begin x ... 'end)])
                 old)))
    (printf ">>> ~s\n" (foo (+ 1 2)))
    

    这在模块内部不起作用,仅在 REPL 上起作用——这是一件的事情。也可以在模块中做类似的事情,但如果你要这样做,你也可以使用过程宏(又名syntax-case 宏),其标识符在语法级别和`set! '-ing 它的价值来扩展它。仍然不是一个好主意,并且仍然会导致眼睛流血,但有些人喜欢伤害自己......

    (哦,顺便说一句——即使这样做仍然与所讨论的宏是否卫生完全无关。)

    【讨论】:

    • 谢谢,我必须包含 (require-for-syntax scheme/base) 才能在语法阶段定义 compose?(在 define-syntax 中定义 compose)。你能评论我的幼稚方法(添加到问题中)没有实施吗?天气不实用或与现有语法不一致?
    • 是的,您需要scheme/base 才能获得撰写;但是您可以以任何方式组合宏函数——它们只是从语法到语法的函数,而syntax-rules 是一个方便的(通常是二级)宏,可以生成这样的函数。至于您的幼稚方法,它存在一些基本问题:它试图以某种方式捕获旧语法,但您无法以这种方式获取它的 value ,因此结果是一个扩展为对其自身的调用的宏.另一个问题是尝试使用display 来调试东西——宏不会执行它,它们会扩展到它。
    • 谢谢,我知道我无法以这种方式捕获旧语法,并且它会扩展到自身。我只是认为它很好地解释了我熟悉的语法,并想知道为什么既然它存在于函数级别,为什么它不存在于宏级别,即使似乎没有任何基本的东西阻止编译器这样做。我试图使用 display 作为测试来查看宏是否构造正确,我编辑了我的问题,将我的幼稚宏转换为工作 plt 方案宏。
    • 你的新版本还是有很多问题,但是用这些cmets来描述恐怕效果不好……
    • 感谢您的洞察力并努力消除各种答案中出现的误解。
    【解决方案4】:

    我认为您可以通过使用不卫生的宏来实现这一点,我相信 PLT Scheme 支持。然后,您将使用与常规函数完全相同的机制,因为宏将是碰巧对 S 表达式进行操作的常规函数​​。

    我不知道如何使用卫生宏来做到这一点,但我很惊讶你做不到 - 我会考虑在 PLT 邮件列表中询问。

    【讨论】:

    • 谢谢,我会尝试在某个时候询问邮件列表。如果 plt 中的宏不卫生,我仍然会感到惊讶,但很高兴。我试图用 defmacro 来回答,但我没有找到答案,虽然我不是 defmacro 方面的专家。
    • 在 PLT 中可以做到的——它们的关键不是使用是否卫生的宏,而是使用程序宏层和一些与之配套的反射功能.
    【解决方案5】:

    let* 呢?

    (define foobar
        (let* ((foo (lambda () (display "foo")))
               (bar (lambda () (foo) (display "bar"))) )
                bar))
    

    【讨论】:

    • 谢谢,但我认为您误解了这个问题。我对能够更改全局变量的定义很感兴趣,而以上只是局部的。另外,我的问题是如何使用宏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    • 1970-01-01
    • 1970-01-01
    • 2019-05-07
    • 2012-02-07
    相关资源
    最近更新 更多