代码之家  ›  专栏  ›  技术社区  ›  Davorak

增量宏定义是否可行?

  •  6
  • Davorak  · 技术社区  · 14 年前

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

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

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

    目前我使用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)
    

    如果我错过了一个更好的方法让我知道。

    5 回复  |  直到 14 年前
        1
  •  2
  •   Eli Barzilay    14 年前

    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!”-利用它的价值来扩展它。仍然不是一个好主意,仍然可以导致眼睛流血,但有些人喜欢伤害自己。。。

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

        2
  •  3
  •   Svante    14 年前

    我不认为你可以用宏来做这样的事情。我也不认为尝试有什么意义。

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

        3
  •  3
  •   Rainer Joswig Michael Fox    14 年前

    有了宏,你就可以创建这个星球上最难维护的软件了。

    编辑:在公共Lisp中这是可能的。我不记得我在源代码中见过它。

    在公共Lisp社区中,向函数或宏添加行为通常称为“advice”或“advice”。一些“advise”工具还可以为宏提供建议。

        4
  •  1
  •   Noah Lavine    14 年前

    我想你可以通过使用不卫生的宏来实现这一点,我相信PLT方案支持这些宏。然后您将使用与正则函数完全相同的机制,因为宏将是碰巧在S表达式上操作的正则函数。

        5
  •  0
  •   jdeseno    14 年前

    那怎么办 let*

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