Skip to content

Instantly share code, notes, and snippets.

@aumouvantsillage
Last active July 6, 2020 15:42
Show Gist options
  • Save aumouvantsillage/22b96f2b41f7a849ee21dfebde28ae0d to your computer and use it in GitHub Desktop.
Save aumouvantsillage/22b96f2b41f7a849ee21dfebde28ae0d to your computer and use it in GitHub Desktop.
Syntactic sugar to access Racket struct fields without prefixing them with the struct type name.
#lang racket
(require
syntax/parse/define
(for-syntax racket/syntax))
; Define an instance of a structure:
; - name: the name of the instance
; - sname: the name of the struct type
; - arg ...: the arguments for the struct type constructor
;
; This will create a macro that provides access to the instance and its fields:
; - (name) returns the struct instance
; - (name fname) returns the value of the field fname in the instance
; - (name fname ...) returns as many values as field names
(define-simple-macro (define-instance name:id (sname:id arg ...))
(begin
; Create a hidden instance of the struct type.
(define inst (sname arg ...))
; Create a macro with the given instance name
(define-syntax-parser name
; With no argument, return the instance.
[(_)
#'inst]
; With one argument, call the accessor for the given field name.
[(_ fname:id)
#:with acc (format-id #'fname #:source #'fname "~a-~a" #'sname #'fname)
#'(acc inst)]
; With more than one argument, expand this macro for each field name.
[(_ fname:id (... ...))
#'(values (name fname) (... ...))])))
; Example: a 2D point type.
(struct point (x y) #:transparent)
(define-instance p (point 10 20))
; Print p and its fields.
(printf "p=~a~np.x=~a~np.y=~a~n" (p) (p x) (p y))
; Get both fields in the same expression.
(define-values (x y) (p x y))
(printf "x=~a~ny=~a~n" x y)
; Accessing an undefined field generates a syntax error with appropriate location.
; (printf "p.z=~a~n" (p z))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment