0

所以,我正在寻找一个宏,它可以更轻松地编写将 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))))

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

有一个更好的方法吗?

4

2 回答 2

0

您应该使用语法参数而不是 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)

有关原因的详细信息,请参阅使用语法参数保持清洁

于 2018-08-10T13:14:13.990 回答
0

您不能凭空取材,但要确保它们与您输入的内容相同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)
于 2018-07-16T00:45:42.863 回答