I'm curious to see the macros others have written.
A good place to start: Syntax Parse Examples which purpose was exactly to answer this question.
A super simple macro I'm using quite often:
(define-syntax-rule (ids->assoc id ...)
(list (cons 'id id) ...))
Usage example:
(define x 3)
(define caps 'CAPS)
(ids->assoc x caps) ; -> '((x . 3) (caps . CAPS))
Another one-liner to define a very simple hygienic threading macro:
(define-syntax-parse-rule (with it:id body:expr ...)
(let* ([it body] ...) it))
Usage example:
(with it "Hello World"
(string-downcase it)
(string-split it)
(map string->list it)
(displayln it))
; displays: ((h e l l o) (w o r l d))
I haven't seen this before... the other threading macros I've used shade gently into point-free mania, this one seems more intuitive. Many thanks!
Not the fanciest ones I've come up with, but maybe my most used: macros to make defining parameters a bit more convienent:
#lang racket/base
(require (only-in srfi/235 [boolean make-boolean])
(for-syntax racket/base syntax/parse))
(provide define-parameter define-boolean-parameter)
; (define-parameter foo 1234) etc
(define-syntax (define-parameter stx)
(syntax-parse stx
((define-parameter name:id initial-value:expr)
#'(define name (make-parameter initial-value #f (quote name))))
((define-parameter name:id initial-value:expr guard:expr)
#'(define name (make-parameter initial-value guard (quote name))))
((define-parameter name:id initial-value:expr guard:expr obj-name:id)
#'(define name (make-parameter initial-value guard obj-name)))))
; Parameters that always return #t or #f
(define-syntax (define-boolean-parameter stx)
(syntax-parse stx
((define-boolean-parameter name:id)
#'(define-parameter name #t make-boolean))
((define-boolean-parameter name:id initial-value:boolean)
#'(define-parameter name initial-value make-boolean))
((define-boolean-parameter name:id initial-value:boolean obj-name:id)
#'(define-parameter name initial-value make-boolean obj-name))))
(Part of my soup-lib
package)
Another one I've been playing with, a version of case
that uses predicates instead of list membership. Demonstrates using custom syntax classes to break the pattern matching up into manageable pieces, and some more complicated syntax-parse
patterns involving alternatives and optional matches:
(define-syntax (case-when stx)
(define-syntax-class clause
#:literals (=>)
(pattern (~or* (pred:expr => func:expr) (pred:expr body:expr ...+))
#:fail-when (free-identifier=? #'pred #'else) #f))
(define-syntax-class else-clause
#:literals (else =>)
(pattern (~or* (else => func:expr) (else body:expr ...+))))
(syntax-parse stx
[(_ val:expr cl:clause ...+ (~optional else-cl:else-clause))
#'(let ([obj val])
(cond
[(cl.pred obj) (~? (cl.func obj) (~@ cl.body ...))] ...
(~? (else (else-cl.func obj)) (~? (else else-cl.body ...)))))]))
Sample usage:
(case-when "abcd"
[integer? 'integer]
[symbol? 'symbol]
[else 'other])