代码之家  ›  专栏  ›  技术社区  ›  Steven Huwig

您使用Scheme宏的目的是什么?[关闭]

  •  10
  • Steven Huwig  · 技术社区  · 16 年前

    许多宏的例子似乎都是关于隐藏lambda的,例如在cl中使用open file。我正在寻找宏的一些更奇特的用法,特别是在plt方案中。我想知道什么时候考虑使用宏还是使用函数。

    10 回复  |  直到 15 年前
        1
  •  6
  •   Nathan Shively-Sanders    16 年前

    我只使用方案宏( define-syntax )对于像更好的lambda语法这样的小东西:

    (define-syntax [: x]
      (syntax-case x ()
        ([src-: e es ...]
         (syntax-case (datum->syntax-object #'src-: '_) ()
           (_ #'(lambda (_) (e es ...)))))))
    

    它让你写作

    [: / _ 2]  ; <-- much better than (lambda (x) (/ x 2))
    

    Dan Friedman使用宏实现了一个令人费解的OO: http://www.cs.indiana.edu/~dfried/ooo.pdf

    但老实说,所有的 有用的 我定义的宏是从中窃取的 Paul Graham's On Lisp 而且通常更容易用 defmacro ( define-macro 在PLT方案中)。例如, aif 很难看 定义语法 .

    (define-syntax (aif x)
      (syntax-case x ()
        [(src-aif test then else)
         (syntax-case (datum->syntax-object (syntax src-aif) '_) ()
           [_ (syntax (let ([_ test]) (if (and _ (not (null? _))) then else)))])]))
    

    定义语法 很奇怪的是,它只适用于非常简单的宏,您很高兴无法捕获变量;以及非常复杂的宏DSL,您很高兴无法捕获变量。 容易地 . 在第一种情况下,您希望在不考虑代码的情况下编写代码,而在第二种情况下,您已经充分考虑了DSL,因此您愿意在 syntax-rules / syntax-case 不是为了避免迷惑错误而设计的语言。


    但我在方案中使用的宏不多。惯用方案非常实用,以至于很多时候你只想编写一个函数程序,然后隐藏一些lambda。我开始了函数训练,现在相信如果你有一个懒惰的语言或者一个好的lambda语法,即使这是不必要的,那么宏在纯粹的函数风格中也不是那么有用。

    所以我建议 Practical Common Lisp On Lisp . 如果你想使用PLT方案,我想他们大部分 反宏观 宏将与 定义宏 . 或者只用普通的口齿不清。

        2
  •  8
  •   soegaard    16 年前

    需要宏来实现新的控制结构和新的绑定构造。

    因此,在 http://planet.plt-scheme.org . 在Planet上,您可以浏览文档和代码。

    新控制结构示例:

    http://planet.plt-scheme.org/package-source/soegaard/control.plt/2/0/planet-docs/manual/index.html

    要查找新绑定表单的示例,请查找以“with-”开头的宏。 一个有用的例子在math.plt中也可以找到。

      ; Within a (with-modulus n form1 ...) the return values of
      ; the arithmetival operations +, -, * and ^ are automatically
      ; reduced modulo n. Furthermore (mod x)=(modulo x n) and
      ; (inv x)=(inverse x n).
    
      ; Example: (with-modulus 3 (^ 2 4)) ==> 1
    
      (define-syntax (with-modulus stx)
        (syntax-case stx ()
          [(with-modulus e form ...)
           (with-syntax ([+   (datum->syntax-object (syntax with-modulus) '+)]
                         [-   (datum->syntax-object (syntax with-modulus) '-)]
                         [*   (datum->syntax-object (syntax with-modulus) '*)]
                         [^   (datum->syntax-object (syntax with-modulus) '^)]
                         [mod (datum->syntax-object (syntax with-modulus) 'mod)]
                         [inv (datum->syntax-object (syntax with-modulus) 'inv)])
             (syntax (let* ([n e]
                            [mod    (lambda (x)   (modulo x n))]
                            [inv    (lambda (x)   (inverse x n))]
                            [+      (compose mod +)]
                            [-      (compose mod -)]
                            [*      (compose mod *)]
                            [square (lambda (x) (* x x))]
                            [^      (rec ^ (lambda (a b)
                                             (cond
                                               [(= b 0)   1]
                                               [(even? b) (square (^ a (/ b 2)))]
                                               [else      (* a (^ a (sub1 b)))])))])
                       form ...)))]))
    
        3
  •  7
  •   Pablo Fernandez    16 年前

    我将开始回答最后一个问题。何时使用宏而不是函数。宏做的是函数做不到的事情,函数做的是宏做不到的事情,所以很难将它们混合在一起,但让我们更深入一点。

    当需要计算参数时使用函数,当需要取消计算参数时使用宏。那不是很有用,是吗?当你想用不同的方式写东西时,当你看到一个模式并且你想抽象的时候,你可以使用宏。例如:我定义了三个函数,分别是foo create、foo process和foo destroy,用于不同的foo值和类似的主体,其中唯一的更改是foo。有一个模式,但是对于一个函数来说级别太高了,所以您创建了一个宏。

    在我不起眼的经验中,Scheme中的宏和其他Lisp中的宏一样使用,比如普通的Lisp或 Clojure . 我想这是证据,也许卫生宏不是一个好主意,这里我会与保罗格雷厄姆不同意为什么。这并不是因为有时候你想变得肮脏(不卫生),而是因为卫生宏最终变得复杂或复杂。

        4
  •  3
  •   Luís Oliveira    16 年前

    实用的公共Lisp,由PeterSeibel编写,对宏有很好的介绍。保罗·格雷厄姆写的Lisp可能是更复杂例子的一个很好来源。此外,还可以查看公共lisp中的内置宏。

        5
  •  3
  •   namin    16 年前

    这个 Automata via Macros 本文提出了一种利用方案中的宏实现有限状态机的函数编程明珠。

    The Reasoned Schemer 以一个完全基于宏的Minikanren实现结束,Minikanren是书中使用的逻辑编程语言。 This paper 比书中更正式、更简洁地介绍了Minikanren及其实现。

        6
  •  1
  •   Matthias Benkard    16 年前

    一个更高级的宏的例子不是lambda形式的伪装是常见的lisp宏 带槽 ,使对象槽访问看起来像普通变量访问:

    (with-slots (state door) car
      (when (eq state :stopped)
        (setq state :driving-around)
        (setq door :closed)))
    

    请注意,这与将槽值绑定到局部变量并访问这些变量不同,因为 带槽 允许您通过setq更改插槽并立即看到外部更改。

        7
  •  1
  •   Dustin    16 年前

    我有一个 curry 当我在手掌上做很多计划的时候。它非常方便。

        8
  •  1
  •   grettke    16 年前

    Scheme宏允许您添加原始语言作者不包括自己的特性;这就是宏背后的整个哲学。

    这里有一个很小的例子:PLT方案提供了一种语言来编写称为幻灯片的演示文稿。我使用宏将幻灯片编号与幻灯片关联起来,以便更轻松地管理它们。

        9
  •  1
  •   Robert Fisher    15 年前

    我编写了一个宏,它提供了中缀语法。没有太花哨的;没有优先权。虽然我_m通常可以使用前缀语法,但我更喜欢<和>的中缀。

        10
  •  0
  •   leppie    16 年前

    我在程序不充分时使用它们。