Dan D.
Dan D.

Reputation: 8567

Scheme/Racket: How to do repeating in defining syntax

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

Answers (1)

Alex Knauth
Alex Knauth

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

Related Questions