For switch
I recommend making a helper macro that switches on a value - this avoids the problem of evaluating the expr
in (switch expr clause ...)
more than once.
Below I used the identifier else
to indicate the default clause.
Note that syntax-parse
try the patterns one-at-a-time. This is used to catch raise syntax errors given faulty input such as (switch)
The initial identifier in the patterns are prefixed with a _
to avoid any problems in recursive macros.
Note that the basic rewrite rule used is:
(switch-value v
[expr result]
clause ...)
==>
(if (equal? v expr)
result
(switch-value v clause ...))
Making the macro recursive is easier than writing one big macro that handles all clauses at once.
#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")])