Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

define* - A single form for making multiple definitions #7

Open
Fictitious-Rotor opened this issue Jul 23, 2021 · 1 comment
Open

Comments

@Fictitious-Rotor
Copy link

Fictitious-Rotor commented Jul 23, 2021

Macro

Make a sequence of definitions - similar to let*.

(define-syntax-parser define*
  [(_ (~or [id:id expr:expr]
           [(idv:id ...+) expr:expr]) ...+)
   #'(begin
       (~? (define id expr)
           (define-values (idv ...) expr)) ...)])

Example

(define*
  [x 4]
  [y 18]
  [(quot rem) (quotient/remainder x y)])

quot rem
; -> 0
; -> 4

Definitions are automatically dispatched either to define or define-values depending on the manner in which identifiers are supplied (define-values is used if the identifiers are contained within a set of parenthesis)

Before and After

This macro saves a lot of unneccesary code when laying out a sequence of definitions

(define-values (pos1-x pos1-y) (values 14 32))
(define-values (pos2-x pos2-y) (values -24 5))
(define-values (x-diff y-diff) (values (- pos2-x pos1-x) (- pos2-y pos1-y)))
(define sqr (curryr expt 2))
(define distance (sqrt (+ (sqr x-diff) (sqr y-diff))))

;; Would become...

(define*
  [(pos1-x pos1-y) (values 14 32)]
  [(pos2-x pos2-y) (values -24 5)]
  [(x-diff y-diff) (values (- pos2-x pos1-x) (- pos2-y pos1-y))]
  [sqr (curryr expt 2)]
  [distance (sqrt (+ (sqr x-diff) (sqr y-diff)))])

;; Which is much less visually noisy

Inner workings

The macro works by accepting either type of clause (single or multiple values)

(~or [id:id expr:expr]
     [(idv:id ...+) expr:expr]) ...+

Resulting in a sequence of patterns, each of which bind either id or a list of idv - as well as expr
The macro then uses the ~? fallthrough syntax to choose which syntax to produce in response.

(~? (define id expr)
    (define-values (idv ...) expr)) ...

If id is not bound then the syntax containing idv will be produced instead.
The ellipsis syntax then repeats this for the whole list of patterns.

Previous iterations

I've unearthed an older version of this macro, which made use of recursive expansion

(define-syntax-parser define*
  [(_ (id:id expr:expr) next ...+)
   #'(begin
       (define id expr)
       (define* next ...))]
  [(_ (id:id expr:expr))
   #'(define id expr)])

Of course this macro does not support definitions that bind multiple identifiers at once - although it does handily demonstrate recursive macros.

Licence

Please confirm that you are submitting this code under the same MIT License that the Racket language uses. https://github.com/racket/racket/blob/master/racket/src/LICENSE-MIT.txt
Please confirm that the associated text is licensed under the Creative Commons Attribution 4.0 International License http://creativecommons.org/licenses/by/4.0/

I confirm that the code is under the same license as the Racket language, and associated text is under Creative Commons Attribution 4.0 International License

Contact

I've already submit a macro, but I'd like to continue contributing to this resource!

@spdegabrielle
Copy link
Contributor

Thank you for your contribution!

If you haven’t already please take the time to fill in the form https://forms.gle/Z5CN2xzK13dfkBnF7

Bw
Stephen

bennn added a commit to syntax-objects/syntax-parse-example that referenced this issue Oct 2, 2021
bennn added a commit to syntax-objects/syntax-parse-example that referenced this issue Oct 27, 2021
bennn added a commit to syntax-objects/syntax-parse-example that referenced this issue Oct 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants