关于Racket宏的两个问题

时间:2017-01-10 08:32:51

标签: macros scheme racket

  1. 关于卫生宏

    我不完全了解宏观工作的卫生程度。这是两个例子 第一个是:

  2. 
        #lang racket
        (define-syntax (g stx)
          (syntax-case stx ()
            ([_ arg]
             #'(display arg))))
    
        (let ([display 1])
          (g 3))
    

    这很好但是这个:

    
        #lang racket
        (define-syntax (g stx)
          (syntax-case stx ()
            ([_ arg]
             #'(display arg))))
    
        (define display 1)
    
        (g 3)
    

    会引发异常。如何解释这两种情况的区别?

    1. 如何定义像这样的宏

      我想定义一个宏来允许在球拍中使用匿名递归函数。 这个不起作用,因为模块中没有定义recur:

    2. 
          #lang racket
          (define Z
            (λ(recur)
              ((λ(x) (recur (λ(y) (x x) y)))
               (λ(x) (recur (λ(y) (x x) y))))))
      
          (define-syntax-rule (R proc)
            (Z (λ(recur) proc)))
      
          ((R (λ(n)
                (if [= n 1]
                    1
                    (* n (recur (- n 1)))))) 3)
      

      如何实现这一目标?

2 个答案:

答案 0 :(得分:3)

要回答你的第一个问题,你在这里忘记的事情就是当你做这样的模块级别define时,该定义将被绑定到整个模块。所以,你可以理论上写下你的第二个代码块:

#lang racket
(let ([display 1])
  (define-syntax (g stx)
    (syntax-case stx ()
      ([_ arg]
       #'(display arg))))

  (g 3))

现在,为什么会出现错误是有道理的,因为宏中的显示被绑定到1,这不是一个函数。

长话短说,将卫生视为词汇范围。当您定义宏时,display绑定的是什么。 (这与其他语言中的宏相反,当你调用(或者真正展开)宏时,display绑定的是什么,它将是什么

现在,为了回答你的第二个问题,我道歉,但不清楚你在这里要问的是什么。如果你可以稍微清理一下,那么我可以填写这部分答案。

答案 1 :(得分:1)

所以你想打破hygene?您需要让recur拥有原始表单的词汇上下文,以便将recur视为相同的标识符。您可以使用datum->syntax执行此操作,结果可能如下所示:

(define-syntax (recur-λ stx)
  (syntax-case stx ()
    [(_ args body ...)
     (with-syntax ([recur-stx (datum->syntax stx 'recur)])
       #'(Z (λ (recur-stx)
              (λ args body ...))))]))

现在,只要您的args或正文中的嵌套引入recur,它就会起作用:

; multiple argument recursion
(define Z
  (λ (f)
    ((λ (g) (g g))
     (λ (g)
       (f (λ args (apply (g g) args)))))))


; ackerman    
((recur-λ (m n)
     (cond
       ((= m 0) (+ n 1))
       ((= n 0) (recur (- m 1) 1))
       (else (recur (- m 1) (recur m (- n 1))))))
 3
 6)
; ==> 509

如果你让recur成为一个论点,它将无效:

((recur-λ (recur) (recur 1)) 1)
; ==> error: recur not a procedure

当然,如果您进行嵌套绑定:

((recur-λ (a) 
   (define recur a) 
   (recur 1))
 1)
; ==> error: recur not a procedure

当然,您可以单步执行宏浏览器,它会告诉您它执行的操作如下:

(expand-once 
 #'(recur-λ (m n)
     (cond
       ((= m 0) (+ n 1))
       ((= n 0) (recur (- m 1) 1))
       (else (recur (- m 1) (recur m (- n 1)))))))

; ==>
; #'(Z
;    (λ (recur)
;      (λ (m n)
;        (cond
;         ((= m 0) (+ n 1))
;         ((= n 0) (recur (- m 1) 1))
;         (else (recur (- m 1) (recur m (- n 1))))))))
相关问题