MatchUtils
Utility macros built on top of match. Provides let-match for
pattern bindings with explicit fallback, and defn-match for
pattern-matching function definitions.
defn-match
Macro
(defn-match name :rest forms)
Defines a pattern-matching function. Each row is a list of patterns
followed by a body. Dispatch is compiled to nested match and case
forms; columns are scored and the most discriminating positions are
tested first.
(deftype Num
(I [Int])
(D [Double]))
(MatchUtils.defn-match add-num
[(Num.I x) (Num.I y)] (Num.I (+ x y))
[(Num.D x) (Num.D y)] (Num.D (+ x y))
[(Num.D x) (Num.I y)] (Num.D (+ x (from-int y)))
[(Num.I x) (Num.D y)] (Num.D (+ (from-int x) y)))
When all rows have the same arity, expands to a single defn with
nested match dispatch. add-num above is a plain function, first-class
and usable in higher-order contexts.
When rows have differing arities, expands to one defn per arity
named name-0, name-1, …, plus a dispatching macro name that
picks the right arity at the call site:
(MatchUtils.defn-match count
[] 0
[(Maybe.Just _)] 1
[(Maybe.Just _) (Maybe.Just _)] 2)
; call sites: (count), (count m), (count m1 m2)
; first-class per arity: count-0, count-1, count-2
; (Array.map count-1 maybes) -- works
; (Array.map count m) -- does NOT work, count is a macro
A row with a variable binding at column k will shadow later rows that have concrete patterns at the same column, since the variable matches anything at that position. Write concrete rows first and catch-alls last.
When invoked as a direct defn body, prefer the qualified form
MatchUtils.defn-match over (use MatchUtils) for the same reason
documented on let-match.
let-match
Macro
(let-match bindings then else)
Pattern-binding form with an explicit fallback. Tries each
pattern expression pair in bindings; if every pattern matches,
evaluates then with the bindings in scope. If any pattern fails,
evaluates else. Both branches must have the same type, so the form
is well-typed regardless of body type.
(MatchUtils.let-match [(Maybe.Just x) (Array.nth &xs 0)]
(IO.println &(fmt "got %d" x))
(IO.println "empty"))
When invoked as a direct defn body, prefer the qualified form
MatchUtils.let-match over (use MatchUtils). A Carp quirk causes
unqualified use-imported macros expanding to match to leak the
pattern variable into value-lookup.