使用语法列表作为函数的形式参数

时间:2016-02-02 00:00:43

标签: macros racket

这是场景:给定[sym ...]形式的模式(例如[a b][a b c d])我想生成(使用宏)函数来连接模式中的符号,但也提供它们作为参数。例如,[a b]转换为

形式的内容
(define (ab a b) 
  body)

this post中,有人通过名为signal-list的语法类帮助我生成函数的名称。在下面的代码中,我可以将signals模式变量与(sig ...)形式的模式匹配,然后我可以使用它来生成所需的函数定义。

(define-syntax (define-something stx)
  (syntax-parse stx
    [(_ (signals:signal-list body ...))
     (syntax-parse #'signals
       [(sig ...)
        #'(define (signals.concatenated-ids sig ...)
               body ...)])]))

与此宏匹配的示例:

(define-something
  ([a b] 'body))

扩展为(define (ab a b) 'body)

但是,如果我想生成多个函数定义,宏如何工作?例如:

(define-something
  ([a b] 'body)
  ([c d e] 'body))
=>
(begin (define (ab a b) 'body)
       (define (cde c d e) 'body))

我可以在第一个语法分析的模式中添加省略号:

(_ (signals:signal-list body ...) ...)

但是我不能使用第二个语法分析来匹配signals,因为它需要省略号。是否有一种不同的方法来“解构”signals,以便我可以将其内容用作函数的形式参数,这与使用省略号兼容?

1 个答案:

答案 0 :(得分:2)

要直接回答您的问题,您可以将#'(signals ...)(代替现有的#'signals)传递给内部syntax-parse调用。

作为一个概念证明,我写了一个syntax-case版本的宏(因为我还不知道syntax-parse)。您应该能够轻松地将相同的技术适应syntax-parse

(define-syntax (define-something outerstx)
  (define (make-name paramstx)
    (datum->syntax outerstx
                   (string->symbol
                    (apply string-append
                           (map symbol->string (syntax->datum paramstx))))))

  (define (make-names innerstx)
    (syntax-case innerstx ()
      (()
       #'())
      (((param ...) rest ...)
       (with-syntax ((name (make-name #'(param ...)))
                     ((next ...) (make-names #'(rest ...))))
         #'(name next ...)))))

  (syntax-case outerstx ()
    ((_ ((param ...) body ...)
        ...)
     (with-syntax (((name ...) (make-names #'((param ...) ...))))
       #'(define-values (name ...)
           (values (lambda (param ...)
                     body ...)
                   ...))))))