-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgeneric.rkt
More file actions
137 lines (113 loc) · 4.84 KB
/
generic.rkt
File metadata and controls
137 lines (113 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#lang racket
(require "applicability.rkt")
(require "utils.rkt")
(provide (all-defined-out))
(define *generic-procedure-metadata-table* (make-weak-hasheqv))
(define (generic-procedure? key)
(hash-has-key? *generic-procedure-metadata-table* key))
(define (generic-procedure-metadata object)
(hash-ref *generic-procedure-metadata-table* object))
(define (set-generic-procedure-metadata! key metadata)
(when (generic-procedure? key)
(let ([existing-metadata (hash-ref *generic-procedure-metadata-table* key)])
(unless (eqv? metadata existing-metadata)
(error "Cannot change metadata for:" key metadata existing-metadata))))
(hash-set! *generic-procedure-metadata-table* key metadata))
(define (error-generic-procedure-handler name)
(lambda args
(error "Inapplicable generic procedure:" name args)))
(struct generic-metadata (name arity dispatcher getter default-getter))
(define (make-generic-metadata name arity dispatcher [getter #f] [default-getter #f])
((dispatcher 'set-default-handler!) default-getter)
(generic-metadata name arity dispatcher
(dispatcher 'get-handler)
(dispatcher 'get-default-handler)))
(define (generic-procedure-constructor dispatch-store-maker)
(λ (name arity default-handler)
(let ([metadata (make-generic-metadata
name arity (dispatch-store-maker)
(or default-handler
(error-generic-procedure-handler name)))])
(define (the-generic-procedure . args)
(generic-procedure-dispatch metadata args))
(set-generic-procedure-metadata! the-generic-procedure
metadata)
the-generic-procedure)))
(define (make-simple-dispatch-store)
(let ([rules '()]
[default-handler #f])
(define (get-handler args)
(let ([rule (findf (λ (rule)
(predicates-match? (car rule) args))
rules)])
(when rule (cdr rule))))
(define (add-handler! applicability handler)
(for-each (λ (predicates)
(set! rules
(list-updatef
rules
(λ (p) (equal? (car p) predicates))
(cons predicates handler))))
;; (let ([p (assoc predicates rules)])
;; (if p
;; (set-cdr! p handler)
;; (set! rules (cons (cons predicates handler)
;; rules))))
applicability))
(define (get-default-handler) default-handler)
(define (set-default-handler! handler)
(set! default-handler handler))
(λ (message)
(case message
[(get-handler) get-handler]
[(add-handler!) add-handler!]
[(get-default-handler) get-default-handler]
[(set-default-handler!) set-default-handler!]
[(get-rules) (λ () rules)]
[else (error "Unknown message: " message)]))))
(define (define-generic-procedure-handler generic-procedure applicability handler)
(((generic-metadata-dispatcher
(generic-procedure-metadata generic-procedure))
'add-handler!)
applicability
handler))
(define (generic-procedure-dispatch metadata args)
(let ([handler (get-generic-procedure-handler metadata args)])
(apply handler args)))
(define (get-generic-procedure-handler metadata args)
(or ((generic-metadata-getter metadata) args)
((generic-metadata-default-getter metadata))))
(define (generic-procedure-name proc)
(generic-metadata-name (generic-procedure-metadata proc)))
(define (generic-procedure-arity proc)
(generic-metadata-arity (generic-procedure-metadata proc)))
(define (generic-procedure-rules proc)
(([generic-metadata-dispatcher (generic-procedure-metadata proc)] 'get-rules)))
(define (generic-procedure-handlers proc)
(map cdr (generic-procedure-rules proc)))
(define (assign-handler!* proc handler preds)
(define-generic-procedure-handler
proc
preds
handler))
(define (assign-handler! proc handler . preds)
(assign-handler!* proc handler (apply match-args preds)))
(define simple-generic-procedure
(generic-procedure-constructor make-simple-dispatch-store))
(define-syntax (define/generic stx)
(syntax-case stx ()
[(_ (proc-name id ...))
#'(define/generic (proc-name id ...) #f)]
[(_ (proc-name id ...) default-handler)
#`(define proc-name
(simple-generic-procedure (quote proc-name)
#,(length (syntax->list #'(id ...)))
default-handler))]))
(define-syntax (define/implementation stx)
(syntax-case stx ()
[(_ (proc-name (id pred) ...) body ...)
#'(define-generic-procedure-handler proc-name (match-args pred ...)
(lambda (id ...)
body ...))]))
(define (any-type? . args)
#t)