Lisp 你需要做的事情是什么';你用过Scheme宏吗?

Lisp 你需要做的事情是什么';你用过Scheme宏吗?,lisp,scheme,macros,racket,Lisp,Scheme,Macros,Racket,许多宏的示例似乎都是关于隐藏lambda的,例如在CL中使用openfile。我正在寻找宏的一些更奇特的用途,特别是在PLT方案中。我想知道什么时候考虑使用宏和使用函数。 < P>我将开始回答最后一个问题。何时使用宏而不是函数。宏做了函数做不到的事情,函数做了宏做不到的事情,所以很难将它们混合在一起,但让我们更深入一点 要计算参数时使用函数,要取消计算参数时使用宏。那不是很有用,是吗?当你想用不同的方式写东西,当你看到一个模式,你想抽象时,你可以使用宏。例如:我为不同的foo值定义了三个名为fo

许多宏的示例似乎都是关于隐藏lambda的,例如在CL中使用openfile。我正在寻找宏的一些更奇特的用途,特别是在PLT方案中。我想知道什么时候考虑使用宏和使用函数。

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

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


根据我的经验,Scheme中的宏与其他Lisp中的宏一样多,比如Common Lisp或。我想这证明了也许卫生宏不是一个好主意,在这里我不同意Paul Graham的观点。这并不是因为有时你想变得肮脏(不卫生),而是因为卫生宏最终会变得复杂或复杂。

彼得·塞贝尔(Peter Seibel)的实用公共Lisp对宏有很好的介绍。保罗·格雷厄姆(Paul Graham)的《Lisp论》(On Lisp)可能是更复杂例子的一个很好来源。另外,请看一下Common Lisp中的内置宏。

我只使用Scheme宏(
定义语法
)来处理一些小问题,例如更好的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))
define syntax
很奇怪,因为它只适用于非常简单的宏,您很高兴无法捕获变量;还有非常复杂的宏DSL,您很高兴无法轻松捕获变量。在第一种情况下,您希望编写代码而不去考虑它,而在第二种情况下,您已经对DSL考虑得够多了,因此您愿意使用
语法规则
/
语法案例
语言编写部分代码,该语言不是Scheme,以避免使bug神秘化


但我在Scheme中不太使用宏。惯用方案的功能非常强大,很多时候,您只想编写一个功能性程序,然后隐藏一些lambda。我上了函数火车,现在相信如果你有一个懒惰的语言或lambda的好语法,即使这是没有必要的,所以宏在纯函数风格中也不是那么有用


因此,我推荐并推荐。如果您想使用PLT方案,我认为他们的大多数
defmacro
宏将与
define macro
一起使用。或者只使用Common Lisp。

一个更高级的宏(不是lambda形式的伪装)的例子是Common Lisp的宏,带有插槽,这使对象插槽访问看起来像普通变量访问:

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

请注意,这与将插槽值绑定到本地变量并访问这些变量不同,因为使用插槽可以通过SETQ更改插槽,并立即查看外部更改。

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

因此,请在下面的位置查找这些类型的构造。 在PLaneT,您可以浏览文档和代码

新控制结构的示例:

要查找新绑定表单的示例,请查找以“with-”开头的宏。 另一个有用的例子是来自PLaneT的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 ...)))]))
本文提出了一种用宏实现有限状态机的函数式编程方法


本书以一个完整的基于宏的miniKanren实现作为结尾,miniKanren是本书中使用的逻辑编程语言。与本书相比,本书更正式、更简洁地介绍了miniKanren及其实现。

当程序不满足要求时,我会使用它们

当我过去在掌上做很多计划时,我有一个
curry
宏。它非常方便。

Scheme宏允许您添加原始语言作者自己没有包含的功能;这就是宏背后的全部哲学


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

我编写了一个提供中缀语法的宏。不要太花哨;没有优先权。虽然我通常对前缀语法很在行,但我更喜欢

Scheme宏的中缀!=公共Lisp宏setq的使用实际上被弃用,取而代之的是setf。如果像这样的例子使用setf,那么对于新的(普通的)口齿不清的人来说就不那么令人困惑了。“因为卫生宏最终会变得复杂或复杂”——我不认为这是因为卫生本身;更可能的原因是Scheme宏是“高级”的,必须用Scheme以外的语言编写(就我而言,Scheme远不如Scheme本身方便!)这就是为什么我喜欢Common Lisp,并且仍然在Scheme中使用define宏,尽管R5R有这种奇怪的语法规则…:-)PLT计划现在称为Racket。请看,通过宏链接的自动机是纯金的。我有一个巨大的啊哈!读它的那一刻+如果你使用一个语法参数,
aif
的定义(和卫生性!):`(定义语法参数it#f)(定义语法aif(语法解析器[(u-test-then-else)#’(let([result test])(语法参数化([it(make-rename-transformer-result)](If-result-then-else))))
  ; 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 ...)))]))