Skip to content

Instantly share code, notes, and snippets.

@branneman
Last active May 24, 2021 13:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save branneman/d0ccb66bdf7671d09df3ec2b56bc3218 to your computer and use it in GitHub Desktop.
Save branneman/d0ccb66bdf7671d09df3ec2b56bc3218 to your computer and use it in GitHub Desktop.
Racket: Macro's
#lang racket/base
(require (for-syntax racket/base))
; Reading Quotes
; see: https://docs.racket-lang.org/reference/reader.html
; ' quote #' syntax
; ` quasiquote #` quasisyntax
; , unquote #, unsyntax
; ,@ unquote-splicing #,@ unsyntax-splicing
; simple literal
(define stx0a (syntax (if #t "yes" "no")))
(define stx0b #'(if #t "yes" "no"))
; (println (list stx0a stx0b))
; quasisyntax + unsyntax
(define stx1 (syntax 42))
(define stx1a
(quasisyntax (define answer (unsyntax stx1))))
(define stx1b
#`(define answer #,stx1))
; (println (list stx1a stx1b))
; unsyntax-splicing
(define stx2 (list (syntax 1300) (syntax 37)))
(define stx2a
(quasisyntax (sum (unsyntax-splicing stx2))))
(define stx2b
#`(sum #,@stx2))
; (println (list stx2a stx2b))
; discards metadata from nested syntax
(define datum (syntax->datum (syntax (if #t "yes" "no"))))
; specifying #f to create syntax without metadata
(define stx (datum->syntax #f (quote (if #t "yes" "no"))))
; running arbitrary code at compile time
(begin-for-syntax
(println "compile time!"))
; defining functions for use at compile time
(define-for-syntax (macro-helper stx)
stx)
#lang racket/base
(require (for-syntax racket/base))
(define-syntax (when stx)
(let ([condition (cadr (syntax-e stx))]
[body (cddr (syntax-e stx))])
#`(if #,condition
(begin #,@body)
(void))))
; (when (> 1300 37) (display "1300 is greater than ") (displayln "37"))
(define-syntax (unless stx)
(let ([condition (cadr (syntax-e stx))]
[body (cddr (syntax-e stx))])
#`(when (not #,condition)
#,@body)))
; (unless (> 3.14 42) (display "42 is greater than ") (displayln "3.14"))
(define-syntax (while stx)
(let ([condition (cadr (syntax-e stx))]
[body (cddr (syntax-e stx))])
#`(let while ([last-result (void)])
(cond
[#,condition
(while (begin #,@body))]
[else
last-result]))))
; (define y 1) (while (< y 9) (println y) (set! y (add1 y)) y)
(define-syntax (until stx)
(let ([condition (cadr (syntax-e stx))]
[body (cddr (syntax-e stx))])
#`(while (not #,condition)
#,@body)))
; (define x -9) (until (zero? x) (println x) (set! x (add1 x)) x)
#lang racket/base
(require (for-syntax racket/base
racket/match))
;
; define-syntax + match
;
(define-syntax (if/v0 stx)
(match (syntax->list stx)
[(list _ condition true-expr false-expr)
(datum->syntax stx `(cond [,condition ,true-expr]
[else ,false-expr]))]))
; (println (if/v0 #t "yes" "no"))
;
; define-syntax + syntax-case
; syntax-case matches a pattern to a syntax object
; (no quasi-quoting and unquoting because it's using pattern variables)
; (syntax-case <id> () [<pattern> <body>])
;
(define-syntax (if/v1 stx)
(syntax-case stx ()
[(_ condition true-expr false-expr)
#'(cond [condition true-expr]
[else false-expr])]))
; (println (if/v1 #t "yes" "no"))
(define-syntax (while/v1 stx)
(syntax-case stx ()
[(_ condition body ...)
#'(let _while ([last-result (void)])
(cond
[condition (_while (begin body ...))]
[else last-result]))]))
; (define y1 0) (while/v1 (< y1 9) (println y1) (set! y1 (add1 y1)) y1)
;
; define-syntax + syntax-rules
;
(define-syntax when/v2
(syntax-rules ()
[(_ condition body ...)
(if condition (begin body ...))]))
; (when (> 1300 37) (display "answer: ") 42)
;
; define-syntax + with-syntax
; with-syntax matches and binds all patterns to pattern variables in the body
; (with-syntax ([<pattern> <syntax>] ...) <body> ...+)
;
(define-syntax (until/v3 stx)
(with-syntax ([(_ condition body ...) stx])
#'(while/v1 (not condition) body ...)))
; (define y3 8) (until/v3 (zero? y3) (println y3) (set! y3 (sub1 y3)) y3)
;
; define-syntax-rule
; (just a shorthand for define-syntax + syntax-case)
;
(define-syntax-rule (if/v4 condition true-expr false-expr)
(cond [condition true-expr]
[else false-expr]))
; (println (if/v4 #t "yes" "no"))
(define-syntax-rule (until/v4 condition body ...)
(while/v1 (not condition) body ...))
; (define y4 8) (until/v4 (zero? y4) (println y4) (set! y4 (sub1 y4)) y4)
#lang racket/base
(require (for-syntax racket/base)
racket/stxparam)
(define-syntax-parameter it
(lambda (stx)
(raise-syntax-error (syntax-e stx) "can only be used inside aif")))
(define-syntax-rule (aif condition true-expr false-expr)
(let ([tmp condition])
(if tmp
(syntax-parameterize ([it (make-rename-transformer #'tmp)])
true-expr)
false-expr)))
; (aif ((λ () (+ 1300 37))) (println it) #f)
#lang racket/base
(require (for-syntax racket/base
syntax/parse))
(define-syntax (when stx)
(syntax-parse stx
[(_ condition body ...)
#'(if condition
(begin body ...)
(void))]))
; (when (> 1300 37) (display "1300 is greater than ") (displayln "37"))
(define-syntax (while stx)
(syntax-parse stx
[(_ condition body ...)
#'(let while ([last-result (void)])
(cond
[condition
(while (begin body ...))]
[else
last-result]))]))
; (define x 1) (while (< x 9) (println x) (set! x (add1 x)) x)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment