Reputation: 8567
I can define the infix '+' as below in Racket:
(require syntax/parse/define (only-in racket (#%app racket:#%app)))
(define-syntax-parser #%app
[(_ Value1 {~datum +} Value2)
#'(+ Value1 Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)]
)
(displayln (1 + 2))
I want to add multiple infix '+' using ~between
but it doesn't work:
(require syntax/parse/define (only-in racket (#%app racket:#%app)))
(define-syntax-parser #%app
[(_ {~between {Value1 {~datum +}} 1 100} Value2)
#'(+ Value1 Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)]
)
(displayln (1 + 2))
The syntax in Racket is here: https://docs.racket-lang.org/syntax/stxparse-patterns.html with ~between
but no ~repeat
.
How to use ~between property to repeat items in syntax?
I have a work-around but it doesn't look pure multiple infix +
, need to wrap every left entry in brackets:
(require syntax/parse/define (only-in racket (#%app racket:#%app)))
(define-syntax-parser #%app
[(_ {Value1 {~datum +}} ... Value2)
#'(+ Value1 ... Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)]
)
(displayln ({1 +} {2 +} 3))
Upvotes: 2
Views: 140
Reputation: 8373
What you want is a combination of ~seq
and ...+
.
(define-syntax-parser #%app
[(_ {~seq Value1 {~datum +}} ...+ Value2)
#'(+ Value1 ... Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)])
The ~seq
matches a sequence of things without requiring them to be grouped by brackets as your workaround did.
The ...+
is a repetition pattern to match one-or-more things, as opposed to zero-or-more. This makes sure that (f)
isn't accidentally interpreted as (+ f)
.
One more note, when you're defining #%app
directly, as opposed to defining under a different name and then renaming the export, you need to be extra careful about implicit recursive uses. For instance (+ + x)
is an infinite loop. To fix that you could use racket:#%app
in both outputs, like #'(racket:#%app + Value1 ... Value2)
.
(define-syntax-parser #%app
[(_ {~seq Value1 {~datum +}} ...+ Value2)
#'(racket:#%app + Value1 ... Value2)]
[(_ Xs ...)
#'(racket:#%app Xs ...)])
Upvotes: 4