【问题标题】:Keyword and default argument macro interfering with variable arguments in Racket关键字和默认参数宏干扰球拍中的可变参数
【发布时间】:2016-08-09 15:25:19
【问题描述】:

我正在使用此页面上提到的宏 (Macro for keyword and default values of function arguments in Racket),它允许我将 {arg_name arg_value} 用于默认和命名参数(不需要 #:key_name)。否则它可以正常工作,但它会干扰具有可变参数(fnname . vars)的函数声明。该错误只是“错误的语法”。如何纠正?感谢您的 cmets / 答案。

编辑:我当前的代码是:

(require syntax/parse/define ; for define-simple-macro
         (only-in racket [define old-define] [#%app old-#%app])
         (for-syntax syntax/stx)) ; for stx-map

(begin-for-syntax
  ;; identifier->keyword : Identifer -> (Syntaxof Keyword)
  (define (identifier->keyword id)
    (datum->syntax id (string->keyword (symbol->string (syntax-e id))) id id))
  ;; for use in define
  (define-syntax-class arg-spec
    [pattern name:id
             ;; a sequence of one thing
             #:with (norm ...) #'(name)]
    [pattern {name:id default-val:expr}                 ; rn: ch if {} needed here; since works well with [] here; 
             #:when (equal? #\{ (syntax-property this-syntax 'paren-shape))
             #:with name-kw (identifier->keyword #'name)
             ;; a sequence of two things
             #:with (norm ...) #'(name-kw {name default-val})]))

(define-syntax-parser define         ; instead of define-simple-macro; 
  [(define x:id val:expr)
   #'(old-define x val)]
  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)])

(begin-for-syntax
  ;; for use in #%app
  (define-syntax-class arg
    [pattern arg:expr
             #:when (not (equal? #\{ (syntax-property this-syntax 'paren-shape)))
             ;; a sequence of one thing
             #:with (norm ...) #'(arg)]
    [pattern {name:id arg:expr}
             #:when (equal? #\{ (syntax-property this-syntax 'paren-shape))
             #:with name-kw (identifier->keyword #'name)
             ;; a sequence of two things
             #:with (norm ...) #'(name-kw arg)]))

(require (for-syntax (only-in racket [#%app app])))

(define-simple-macro (#%app fn arg:arg ...)
  #:fail-when (app equal? #\{ (app syntax-property this-syntax 'paren-shape))
  "function applications can't use `{`"
  (old-#%app fn arg.norm ... ...))

我不确定要更改哪个部分。如果我删除最后一部分(定义简单宏),{} 中的命名/默认参数不起作用。

进一步编辑:我已将代码修改如下:

(define-syntax-parser define         ; instead of define-simple-macro; 
  [(define x:id val:expr)
   #'(old-define x val)]
  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)]
  [(define (fn . vars) body ...+)
   #'(old-define (fn . vars) body ...)]      )

它的工作原理:

(define (testvars . vars)
  (println (list? vars))
  (for ((item vars))(println item))     )

(testvars 1 2 3)
#t
1
2
3

但为什么我还需要“(define-simple-macro ..”部分?另外,为什么我需要2个“(begin-for-syntax..”定义)?

再次编辑:进一步修改:

(define-syntax-parser define         
  [(define x:id val:expr)
   #'(old-define x val)]
  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)]
  [(define (fn arg:arg-spec ... . vars) body ...+)                
   #'(old-define (fn arg.norm ... ... . vars) body ...)]
  )

Above 最终适用于命名参数和变量参数,例如(fnname {x 0} {y 1} 10 20 30),感谢下面 cmets 中 @AlexKnauth 的所有帮助。

【问题讨论】:

  • 该问题/答案中的 define 宏不支持声明“rest”参数。当我写它的时候,我不想用不相关的特性来混淆实现。
  • 虽然实际上,尝试自己扩展它应该不是很难。而不是define-simple-macro,您必须使用define-syntax-parser,有两种情况,一种用于没有其余参数的情况,另一种用于有剩余参数的情况。
  • define 是您需要更改的那个,它已经用define-syntax-parser 编写了。我忘记了,但这使这更容易。您只需在现有的 define 宏中添加另一个案例。
  • 最后一个define-simple-macro 定义了#%app 宏,它重新定义了函数应用程序的样子。如果你忽略它,你将可以拨打(greet #:hello "hi"),但不能拨打(greet [hello "hi"])
  • 另外,您可能应该添加修改后的define 宏作为答案,尽管应该通过编写vars:id 来确保vars 是一个标识符,并且您应该确保您可以有一些正常的参数后跟 ` 。 rst-id`也是

标签: macros scheme racket


【解决方案1】:

正如我们在 cmets 中发现的那样,您所要做的就是在 define 宏中添加第三种情况,类似于第二种情况,但在模式中的 arg:arg-spec ... 之后添加一个 . rst,然后再一次在模板中的arg.norm ... ... 之后。

第二种情况是

  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)]

新案例类似,但添加了. rst

  [(define (fn arg:arg-spec ... . rst) body ...+)                
   #'(old-define (fn arg.norm ... ... . rst) body ...)]

在上下文中它看起来像这样。

(define-syntax-parser define         
  [(define x:id val:expr)
   #'(old-define x val)]
  [(define (fn arg:arg-spec ...) body ...+)
   #'(old-define (fn arg.norm ... ...) body ...)]
  [(define (fn arg:arg-spec ... . rst) body ...+)                
   #'(old-define (fn arg.norm ... ... . rst) body ...)]
  )

【讨论】:

猜你喜欢
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 2011-05-07
相关资源
最近更新 更多