# match-generics This morning we made [the fastest generics of all time][ctg]. Now, let's make the most flexible ones! They're almost as fast, too. They don't need to have the same number of arguments or use the same names: (define-generic (frotz a b c) (list b a c)) (define-generic (frotz x y) (+ x y)) (list (frotz 1 2 3) (frotz 4 5)) ⇒ ((2 1 3) 9) They can even destructure their arguments: (define-generic (my-map proc (x . xs)) (cons (proc x) (my-map proc xs))) (define-generic (my-map proc ()) '()) (my-map add1 '(1 2 3)) ⇒ (2 3 4) To use predicates, use the form `(? pred var)`, like this: (define-generic (plus (? list? a) (? list? b)) (append a b)) (define-generic (plus (? string? a) (? string? b)) (string-append a b)) (define-generic (plus (? number? a) (? number? b)) (+ a b)) (list (plus "13" "14") (plus 7 22) (plus 13 19) (plus '(a b c) '(1 2 3))) ⇒ ("1314" 29 32 (a b c 1 2 3)) You need to define them in order from least specific to most specific, i.e. define the most specifics last and the fallbacks first. You can even use nested defines! But if you do, each need to use the same inner forms. Only the outer-most form is generic. (define-generic ((frobnicate a) b z) (list a b z)) (define-generic ((frobnicate a) b) (string-append a b)) (let ((hoho (frobnicate "hoho"))) (list (hoho 1 2) (hoho " and such"))) ⇒ (("hoho" 1 2) "hoho and such") ## Implementation By now, maybe some of the long-time readers in the audience has guessed what is going on. Each generic is defined using a clause from [matchable]! The implementation using some miscellaneous [brev-separate] stuff is just… **five lines!** (define-for-syntax gentable (call-table)) (define-ir-syntax (define-generic (name . pattern) . body) (cons 'match-define (gentable (strip-syntax name) (cons (cons name pattern) body)))) [ctg]: https://idiomdrottning.org/call-table-generics "call-table-generics" [matchable]: http://wiki.call-cc.org/eggref/5/matchable [brev-separate]: https://idiomdrottning.org/brev-separate