-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathskell.k
225 lines (173 loc) · 6.29 KB
/
skell.k
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
;;; FIXME (just, in general)
;;; combiners; core
($define! combiner ($class () ()))
($define! vau ($class (combiner) (params eparam body static)))
($define! make-vau (constructor vau))
($define! $vau
;; straight metacircle
($vau (params eparam body) static (vau params eparam body static)))
($define! applicative ($class (combiner) (underlying)))
($define! wrap (constructor applicative))
($define! unwrap ($generic (((applicative underlying)) underlying)))
;($define! macro ($class (combiner) (underlying)))
;($define! $macro
; ($macro (params eparam body) #ignore
; (list macro (list $vau params eparam body))))
($define! make-lambda
($lambda (params body static)
(wrap (make-vau params #ignore body static))))
($define! $lambda
($vau (params body) static (make-lambda params body static)))
($define! eval
($generic (form env)
(((symbol form) env)
($case (lookup form env)
((just value) value)
((nothing) (error "~a unbound" form))))
(((cons combiner combinand) env) (combine combiner combinand env))))
($define! curry
($lambda (fn . left-args)
($lambda (right-args)
(apply fn (append left-args right-args)))))
($define! rcurry
($lambda (fn . right-args)
($lambda left-args
(apply fn (append left-args right-args)))))
($define! combine
($generic
(((applicative combiner) combinand env)
(combine combiner (map (rcurry eval env) combinand) env))
; (((macro macro-combiner) combinand env)
; (eval (combine macro-combiner combinand env) env))
(((vau params eparam body static) combinand env)
(eval body (vau-augment (augment-1 static eparam env) params combinand)))))
($define! augment-1
($lambda (env param arg)
(bindings->environment (list (cons param arg)) env)))
($define! vau-augment
($lambda (env ptree arg)
($letrec ((flatten
($generic
(((symbol name) arg) (list (cons name arg)))
(((cons left right) (cons argl argr)) (append (flatten left argl) (flatten right argr)))
(((ignore) #ignore) ())
(((null) (null)) ()))))
(bindings->environment (flatten ptree arg) env))))
;($define! param->bindings
; ;; ideally this would basically eval in a special sort of way
; ;; but fuck
; ($generic (param arg dyn)
; (((symbol param) arg #ignore) (list param arg))
; (((cons (symbol classname) rest) arg dyn)
; ($case (lookup classname dyn)
; ((just class)
; (apply (destructurer class) (list rest arg dyn)))
; ((nothing) (error "unknown class ~a" classname))))))
;($define! augment
; ($lambda (env params args dyn)
; ;; dyn is needed to get classes... kinda gross?
; (bindings->environment (mappend (rcurry1 param->bindings dyn) params args) env)))
;;; classes
($define! top ($class () ()))
($define! standard-object ($class () (class values)))
($define! slots ($generic (((standard-object #ignore values)) values)))
($define! type ($class () ()))
($define! class ($class (type) (supers fields)))
($define! $class
($vau (supers fields) env
(make-instance class ($if (null? supers) (list standard-object) (map (rcurry eval env) supers)) fields)))
($define! make-instance
;; durf straight metacircular
($lambda (class . values) (make-instance standard-object class values))))
;; in a real implementation these would probably be defined the other way
;; easier to specialize constructor than make-instance, and stuff
($define! constructor
($lambda (class) (curry make-instance class)))
($define! of-class
($lambda (class)
($generic
(((standard-object objclass #ignore)) (eq? objclass class))
((#ignore) ; not a standard-object
#f))))
($define! some1
($generic
(((pred (cons this more))) (or? (call pred this) (some1 pred more)))
((pred (null)) #f)))
($define! subclass?
;; bla bla genericism
($lambda (c1 c2)
;; cut a few metacircles
($cond ((eq? top c2) #t)
((eq? top c1) #f)
((eq? c1 c2) #t)
(#t ($case c1
((standard-object supers #ignore)
(or? (find c2 supers)
(some1 (rcurry subclass? c2) supers))))))))
;;; case
($define! match?
($generic
(((symbol var) #ignore #ignore) #t)
(((ignore) #ignore #ignore) #t)
(((cons class rest) object env)
($if ((of-class (eval class env)) object)
(every? (rcurry match? env) (slots object) rest)
#f))))
($define! pattern->bindings
($generic
(((symbol var) object) (cons var object))
(((ignore) #ignore) ())
(((cons class rest) object)
(mappend pattern->bindings rest (slots object)))))
($define! $case
($vau (form . clauses) env
($let ((object (eval form env)))
($letrec ((rec
($lambda (clauses)
($if (null? clauses)
#inert
($let ((((pattern body) clauses) clauses))
($if (match? pattern object env)
(eval body (bindings->environment (pattern->bindings pattern object) env))
(rec clauses)))))))
(rec clauses)))))
;;; methods
($define! method ($class () ()))
($define! standard-method ($class (method) (op specializers)))
($define! make-method (constructor standard-method))
($define! $method
($vau (sp-args body) env
($let ((split (map ($generic
(((symbol param)) (cons param top))
(((cons name (cons type (null)))) (cons name type)))
sp-args)))
(make-method (map car args) (map cdr args)))))
($define! method-specializers ($generic (((method #ignore specializers)) specializers)))
;; imagine specialized-using-classes or w/e
($define! specialized?
($lambda (method . args)
(every? of-type/standard-class args (method-specializers method))))
;;; environments
($define! environment ($class () ()))
($define! standard-environment ($class (environment) (alist parents)))
($define! parents ($generic (((environment #ignore parents)) parents)))
($define! bindings->environment
($lambda (alist . parents)
(make-instance standard-environment alist parents)))
($define! pick-just
($lambda (fn list)
($letrec ((recur
($generic
(((cons next more))
($case (fn next)
((just val) (just val))
((nothing) (recur more))))
(((null)) (nothing)))))
(recur list))))
($define! lookup
($generic
((name (standard-environment alist parents))
($case (assoc name alist)
((cons #ignore val) (just val))
((null) (pick-just (curry lookup name) parents))))))
;; skipping letrec because it'd either be a bunch of combinator bullshit