Created
April 9, 2019 00:38
-
-
Save rjungemann/84aa57058870d6e556e8f6f326dea384 to your computer and use it in GitHub Desktop.
Racket Multimethods, v1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#lang racket | |
(require compatibility/defmacro | |
racket/stxparam) | |
(define-syntax-parameter current-define-multis (make-hash)) | |
(define-syntax-parameter current-define-multi-fns (make-hash)) | |
(define-macro (define-multi name) | |
(let ([current-define-multis (syntax-parameter-value #'current-define-multis)] | |
[current-define-multi-fns (syntax-parameter-value #'current-define-multi-fns)]) | |
(hash-set! current-define-multis name (make-hash)) | |
(let* ([current-define-multi (hash-ref current-define-multis name)]) | |
(hash-set! current-define-multi-fns | |
name | |
`(λ args | |
(cond | |
; TODO: Raise here | |
[else | |
#f])))))) | |
; TODO: Mutable list instead of mutable hash | |
(define-macro (define-instance name arg-name pred . body) | |
(let* ([current-define-multis (syntax-parameter-value #'current-define-multis)] | |
[current-define-multi-fns (syntax-parameter-value #'current-define-multi-fns)] | |
[current-define-multi (hash-ref current-define-multis name)]) | |
(hash-set! current-define-multi pred body) | |
(let ([conds (map (λ (cnd) | |
(append (list (car cnd)) | |
(cdr cnd))) | |
(hash->list current-define-multi))]) | |
(hash-set! current-define-multi-fns | |
name | |
`(λ ,arg-name | |
,(append '(cond) conds '([else #f]))))))) | |
(define-macro (multi-call name . args) | |
(let* ([current-define-multi-fns (syntax-parameter-value #'current-define-multi-fns)] | |
[current-define-multi-fn (hash-ref current-define-multi-fns name)]) | |
(append (list current-define-multi-fn) args))) | |
; Example | |
(define-multi foo) | |
(define-instance foo $ ; $ is a user-definable variable containing the args | |
(equal? (first $) 'bar) ; predicate | |
#t) ; body | |
(define-instance foo $ | |
(equal? (first $) 'baz) | |
'yes) | |
(multi-call foo 'bar) | |
(multi-call foo 'baz) | |
(multi-call foo 'quux) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment