Scheme racketswitch语句宏

Scheme racketswitch语句宏,scheme,racket,Scheme,Racket,我试图在Racket中创建一个switch语句宏。我很难明白该怎么做。我希望能够使用如下所示的功能 (define x 99) (switch x [3 (displayln "x is 3")] [4 (displayln "x is 4")] [5 (displayln "x is 5")] ['default (displayln "none of the above")]) 我已经尝试过将模式匹配与语法大小写结合使用,但我不确定这是正确的方法。这里的任

我试图在Racket中创建一个switch语句宏。我很难明白该怎么做。我希望能够使用如下所示的功能

(define x 99)

(switch x
    [3 (displayln "x is 3")]
    [4 (displayln "x is 4")]
    [5 (displayln "x is 5")]
    ['default (displayln "none of the above")])

我已经尝试过将模式匹配与语法大小写结合使用,但我不确定这是正确的方法。这里的任何球拍专家都能给我一个正确的方向吗?

对于
开关
我建议制作一个打开值的辅助宏-这避免了在
(开关expr子句…
中多次评估
expr
的问题

下面我使用标识符
else
来表示默认子句

请注意,
语法分析
一次尝试一种模式。如果输入错误,例如
(开关)

模式中的初始标识符前缀为
,以避免递归宏中出现任何问题

请注意,使用的基本重写规则是:

(switch-value v
   [expr result]
   clause ...)

==>

(if (equal? v expr)
    result
    (switch-value v clause ...))
使宏递归比编写一个同时处理所有子句的大型宏更容易

#lang racket

(require (for-syntax syntax/parse))

(define-syntax (switch stx)
  (syntax-parse stx
    [(_switch)
     #'(raise-syntax-error 'switch "value expression and at least one clause expected" stx)]
    [(_switch expr clause ...)
     #'(let ([v expr])
         (switch-value v clause ...))]))

(define-syntax (switch-value stx)
  (syntax-parse stx
    #:literals (else)
    [(_switch-value v)
     #'(raise-syntax-error 'switch "at least one clause is expected" _switch-value)]
    [(_switch-value v [else expr])
     #'expr]
    [(_switch-value v [expr1 expr2] clause ...)
     #'(if (equal? v expr1)
           expr2
           (switch-value v clause ...))]))


(define x 4)

(switch x
  [3 "x is 3"]
  [4 "x is 4"]
  [5 "x is 5"]
  [else (displayln "none of the above")])

我相信不要重新发明完美的轮子,因此这里有一个宏用于将您的
开关
转换为等效的
案例
,只需稍作更改即可使用
默认值
,而不是
默认值
。(我向soegaard道歉,因为我还不知道如何使用
语法解析
,所以我将只使用传统的
语法大小写
。-)

与使用
大小写
相反,使用此
开关
宏的缺点是,您无法区分使用
默认值
匹配符号与使用“一网打尽”符号。因此,使用
case
更好。:-)


我喜欢其他两个答案,但我觉得我们还应该提到现有的
匹配
表单,它(afaict)已经完全满足了您的需求:

#lang racket

(define x 99)

(match x
  [3 (displayln "x is 3")]
  [4 (displayln "x is 4")]
  [5 (displayln "x is 5")]
  [default (displayln "none of the above")])
唯一的变化是:我写
match
而不是
switch
,并且我使用模式
default
而不是引用的
'default
。事实上,任何标识符都可以在这里工作;标识符只是给一个值命名

事实上,match可以做的远不止这些,但这是它的一大用途

如果您只是想练习编写宏,那么您可以忽略以下答案:)。

(语法大小写(默认)stx子句)
(语法解析stx::文字(默认)子句…
的意思是相同的(假设您没有使用任何防护措施。就是这么简单!
(case x
  ((3) (displayln "x is 3"))
  ((4) (displayln "x is 4"))
  ((5) (displayln "x is 5"))
  (else (displayln "none of the above")))
#lang racket

(define x 99)

(match x
  [3 (displayln "x is 3")]
  [4 (displayln "x is 4")]
  [5 (displayln "x is 5")]
  [default (displayln "none of the above")])