Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

@Fictitious-Rotor

Description

@Fictitious-Rotor

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions