方案:define和define-syntax-rule之间的区别

时间:2015-10-13 15:32:36

标签: macros scheme racket

我在Racket中获得了两条if语句指令:

(define (if-fun c thn els) (if c thn els))
(define-syntax-rule (if-mac c thn els) (if c thn els))

有人请介意解释如何评估这两个if语句之间的差异,并提供使用每个if语句定义的示例吗?我很难区分在这个例子中如何评估宏和函数参数。我尝试了一些小例子,如:

(if-fun (> 3 4) true false)  ;; #f
(if-mac (> 3 4) true false)  ;; #f

但很明显,这并没有帮助我区分这两个定义。

-Thanks

2 个答案:

答案 0 :(得分:5)

从您的评论中听起来您已经想到了这一点。关键问题是,什么时候(如果有的话)会对事情进行评估?

另一个关键点是功能和宏完全不同,即使它们的定义和使用看起来都一样。

  • 使用函数和宏的方式完全相同:(thing other stuff)thing是函数还是宏是不明显的。这既好又坏。大多数情况下它非常好。

  • 对于定义事物,使用define-syntax-rule定义宏的方式与函数define的方式非常相似。这既好又坏。当你第一次学习时,我说它大部分都很糟糕 - 因为它很容易让人忘记完全不同的宏来自功能。这可能令人困惑!

  • 调用函数时,在运行时评估所有参数,然后赋予函数。这就是为什么if-fun (/ 1 0)的参数会导致错误的原因。在控制进入if-fun之前,它被评估(并引出除以零误差)。

    (旁注:当您使用懒惰评估或手动" thunks"来调用某个功能时,评估会延迟。if-lazy可以调用thnels过程参数,仅在/需要时。当条件为假时,它甚至不会尝试调用els。)

  • 调用宏

    1. 何时:宏在您的程序运行之前完成其工作。宏在编译时工作,而不是在运行时。

    2. 什么:宏将代码段转换为其他代码段。但是代码还没有被评估。代码仅在运行时稍后进行评估。那么"论证"到if-mac没有被宏评估。他们只是插入真实if表单的代码,这是一个宏(或原始的特殊形式),只评估所需的内容。

最后一个令人困惑的部分是,因为您的示例然后其他表达式没有任何副作用,并且不会有任何副作用导致任何错误,差异不明显。

答案 1 :(得分:0)

(define (verbose arg)
  (display arg) ; display 
  (newline)     ; display newline
  arg))         ; evaluate to arg

(if-fun (verbose (> 3 4)) 
        (verbose 'true) 
        (verbose 'false))
; ==>  false

打印

#f
true
false

宏版本:

(if-mac (verbose (> 3 4)) 
        (verbose 'true) 
        (verbose 'false))
; ==>  false

打印

#f
false

你看到了区别吗?使用过程计算每个参数并将其绑定到变量,然后评估主体。

在宏版本中,代码被转换,然后进行评估。因此,由于谓词为#f,因此从未执行过后续表达式。

如果您尝试制作递归函数:

(define (factorial n)
  (if-fun (<= n 2)
          n
          (* n (factorial (- n 1)))))

(factorial 2)

即使它遇到基本情况,由于所有3个参数都被评估,它将做(因子1),然后(因子0),(因子-1).....到负无穷大。它永远不会返回一个值,但是,它不是尾递归,它会耗尽内存。

(define (factorial n)
  (if-mac (<= n 2)
          n
          (* n (factorial (- n 1)))))

(factorial 2)

评估程序时,可以扩展宏,使其变为:

(define (factorial n)
  (if (<= n 2)
      n
      (* n (factorial (- n 1)))))

就好像你根本没有使用你的宏。如果你有一个宏,它在展开时会打印一些东西,它会在你使用之前为程序中的每次使用打印一次。

就像这样,因为Scheme和Racket都有热切的评价。例如。 #!lazy球拍,这是#!racket的懒惰版本,if和其他特殊形式作为程序制作,因为需要进行评估。懒惰的语言不需要宏。