宏定义中的升序数

bit*_*ips 5 macros scheme racket

我经常使用Racket的模式匹配结构match,我想一种方法来帮助自己调试程序match,并了解Racket/Scheme宏如何工作,将创建一个宏,其中包含匹配模式的信息.

换句话说,我正在寻找创建一个宏,给定:

(match/debug 'two
  ['one 1]
  ['two 2])
Run Code Online (Sandbox Code Playgroud)

输出如下:

Case 2 <-- Printed
2      <-- Returned value
Run Code Online (Sandbox Code Playgroud)

到目前为止,主要障碍是试图使数字表示已解决的案例正确显示.

我的目标是尝试写一些像这样扩展的东西:

(match 'two
  ['one (displayln "Case 1") 1]
  ['two (displayln "Case 2") 2])
Run Code Online (Sandbox Code Playgroud)

但是我无法找出任何方法来生成那些"Case#"字符串.

这是我尝试的宏定义:

(define-syntax-rule (match/debug id [pattern value] ...)
  (let ([index 0])
    (match id
      [(begin
         (set! index (add1 index))
         pattern)
       (printf "Case ~a\n" index)
       value] ...)))
Run Code Online (Sandbox Code Playgroud)

似乎语法match不会让我做这样的事情,但这是我能想到的唯一方法.我只是习惯了Common Lisp的宏风格.

soe*_*ard 5

这是一个解决方案.

辅助函数clauses->numbers返回一个数字列表,从0到小于子句数的数字.然后使用它为每个子句赋予其自己的编号.请注意,此解决方案从0开始计算(而不是在示例中为1).

#lang racket
(require (for-syntax syntax/parse))

(begin-for-syntax
  (require racket/list) ; import range
  (define (clauses->numbers stx)
    (range (length (syntax->list stx)))))

(define-syntax (match/debug stx)
  (syntax-parse stx
    [(_match/debug id [pattern value] ...)
     (with-syntax ([(n ...) (clauses->numbers #'([pattern value] ...))])
       (syntax/loc stx
         (match id
           [pattern (begin (displayln (~a "Case: " n)) value)]
           ...)))]))

(match/debug 'one
  ['one 1]
  ['two 2])

(match/debug 'two
  ['one 1]
  ['two 2])
Run Code Online (Sandbox Code Playgroud)

输出:

Case: 0
1
Case: 1
2
Run Code Online (Sandbox Code Playgroud)