【问题标题】:Racket - Macro - Define Function球拍 - 宏 - 定义功能
【发布时间】:2018-07-14 17:11:36
【问题描述】:

所以,我正在寻找一个宏,它可以更轻松地编写将 s 表达式和列表作为输入的函数,并在列表中的一个 s 表达式与 s 表达式匹配时执行某些操作在输入。我注意到其中许多函数具有相同的外观。

所以,我写了这个:

(define-syntax (ember stx)
  (syntax-parse stx
    [(ember name terminal match recurse) #'(define name (lambda (s l)
                                                          (cond
                                                            [(null? l) terminal]
                                                            [(eq? (car l) s) match]
                                                            [else recurse])))]))

(ember member #f #t (match s (cdr l)))

不幸的是,这不起作用,因为 s 是一个未绑定的标识符。我试图将它用引号括起来,然后在宏中放置一个 eval,但这也导致了一个未绑定的标识符。

所以,我重写了我的代码,如下所示:

(define-syntax (ember stx)
  (syntax-parse stx
    [(ember name terminal match recurse) #'(define name (lambda (s l)
                                                          (cond
                                                            [(null? l) (terminal s l)]
                                                            [(eq? (car l) s) (match s l)]
                                                            [else (recurse s l)])))]))

(ember member (lambda (x y) #f) (lambda (x y) #t) (lambda (x y) (match x (cdr y))))

但是,不幸的是,如果我的匹配定义变得如此复杂,复制成员函数并通过手动编辑终端、匹配和递归选项的位置来创建相同类型的新函数似乎更容易。

有没有更好的方法来做到这一点?

【问题讨论】:

    标签: macros racket function-definition


    【解决方案1】:

    您不能凭空取出sl,但要确保它们与您输入的相同。这样做:

    (define-syntax (ember stx)
      (syntax-parse stx
        [(ember name terminal match recurse)
         (with-syntax ([s (datum->syntax stx 's)]
                       [l (datum->syntax stx 'l)])
           #'(define name (lambda (s l)
                            (cond
                              [(null? l) terminal]
                              [(eq? (car l) s) match]
                              [else recurse]))))]))
    
    (ember member2 #f l (member2 s (cdr l)))
    (member2 'a '(1 2 a 3))
    ; ==> (a 3)
    

    【讨论】:

      【解决方案2】:

      你应该使用Syntax Parameters而不是datum->syntax:

      (define-syntax-parameter s (syntax-rules ()))
      (define-syntax-parameter l (syntax-rules ()))
      
      (define-syntax-rule
        (ember name terminal match recurse)
        (define name
          (lambda (s* l*)
            (syntax-parameterize ([s (make-rename-transformer #'s*)]
                                  [l (make-rename-transformer #'l*)])
              (cond
                [(null? l) terminal]
                [(eq? (car l) s) match]
                [else recurse])))))
      
      (ember member #f l (member s (cdr l)))
      (member 'a '(1 2 a 3))
      ; -> '(a 3)
      

      请参阅Keeping it Clean with Syntax Parameters 了解详情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多