Coverage report: /home/runner/work/geb/geb/src/lambda/lambda.lisp
Kind | Covered | All | % |
expression | 764 | 1211 | 63.1 |
branch | 58 | 94 | 61.7 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
(in-package #:geb.lambda.main)
3
(defclass fun-type (geb.mixins:direct-pointwise-mixin geb.mixins:cat-obj)
11
"Stand-in for the [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ] object. It does not have
12
any computational properties and can be seen as just a function of two arguments
13
with accessors [MCAR][generic-function] to the first argument and
14
[MCADR][generic-function] to the second argument. There is an evident canonical
15
way to associate [FUN-TYPE][class] and [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ]
18
(defun fun-type (mcar mcadr)
19
(make-instance 'fun-type :mcar mcar :mcadr mcadr))
21
(-> index-check (fixnum list) cat-obj)
22
(defun index-check (i ctx)
23
"Given an natural number I and a context, checks that the context is of
24
length at least I and then produces the Ith entry of the context counted
25
from the left starting with 0."
26
(let ((l (length ctx)))
29
(error "Argument exceeds length of context"))))
31
;; Types all terms inside a given lambda term with respect to a context
32
;; with the caveat of producing a stand-in of the exponential object
34
;; We assume that the compiler receives all the info using the exp-aux
35
;; class instead of the usual hom-obj for the well-defp predicate
38
(defgeneric ann-term1 (ctx tterm)
40
"Given a list of [SUBSTOBJ][GEB.SPEC:SUBSTOBJ] objects with
41
[SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ] occurences replaced by [FUN-TYPE][class]
42
and an [STLC][type] similarly replacing type occurences of the hom object
43
to [FUN-TYPE][class], provides the [TTYPE][generic-function] accessor to all
44
subterms as well as the term itself, using [FUN-TYPE][class]. Once again,
45
note that it is important for the context and term to be giving as
46
per above description. While not always, not doing so result in an error upon
47
evaluation. As an example of a valid entry we have
50
(ann-term1 (list so1 (fun-type so1 so1)) (app (index 1) (list (index 0))))
56
(ann-term1 (list so1 (so-hom-obj so1 so1)) (app (index 1) (list (index 0))))
59
produces an error trying to use. This warning applies to other
60
functions taking in context and terms below as well.
62
Moreover, note that for terms whose typing needs addition of new context
63
we append contexts on the left rather than on the right contra usual type
64
theoretic notation for the convenience of computation. That means, e.g. that
65
asking for a type of a lambda term as below produces:
68
LAMBDA> (ttype (term (ann-term1 (lambda (list so1 so0) (index 0)))))
72
as we count indeces from the left of the context while appending new types to
73
the context on the left as well. For more info check [LAMB][class]"))
76
(defmethod ann-term1 (ctx (tterm <stlc>))
81
((absurd tcod term) (absurd tcod (ann-term1 ctx term) :ttype tcod))
82
(unit (unit :ttype so1))
83
((left rty term) (let ((lant (ann-term1 ctx term)))
86
:ttype (coprod (ttype lant) rty))))
87
((right lty term) (let ((rant (ann-term1 ctx term)))
90
:ttype (coprod lty (ttype rant)))))
91
((pair ltm rtm) (let ((lant (ann-term1 ctx ltm))
92
(rant (ann-term1 ctx rtm)))
95
:ttype (prod (ttype lant) (ttype rant)))))
96
((fst term) (let* ((ann-term (ann-term1 ctx term))
97
(type-of-term (ttype (ann-term1 ctx term))))
98
(if (typep type-of-term 'prod)
100
:ttype (mcar type-of-term))
101
(error "type of term not of product type"))))
102
((snd term) (let* ((ann-term (ann-term1 ctx term))
103
(type-of-term (ttype ann-term)))
104
(if (typep type-of-term 'prod)
105
(snd ann-term :ttype (mcadr type-of-term))
106
(error "type of term not of product type"))))
107
((lamb tdom term) (let ((ant (ann-term1 (append tdom ctx) term)))
110
:ttype (fun-type (reduce #'prod tdom
113
((app fun term) (let ((anfun (ann-term1 ctx fun)))
115
(mapcar (lambda (trm) (ann-term1 ctx trm)) term)
116
:ttype (mcadr (ttype anfun)))))
117
((index pos) (index pos
118
:ttype (index-check pos ctx)))
119
((err ttype) (err ttype))
120
((plus ltm rtm) (let ((ant (ann-term1 ctx ltm)))
123
:ttype (ttype ant))))
124
((times ltm rtm) (let ((ant (ann-term1 ctx ltm)))
127
:ttype (nat-width 24))))
128
((minus ltm rtm) (let ((ant (ann-term1 ctx ltm)))
131
:ttype (nat-width 24))))
132
((divide ltm rtm) (let ((ant (ann-term1 ctx ltm)))
135
:ttype (nat-width 24))))
136
((bit-choice bitv) (bit-choice bitv
137
:ttype (nat-width 24)))
138
((lamb-eq ltm rtm) (lamb-eq (ann-term1 ctx ltm)
140
:ttype (coprod so1 so1)))
141
((lamb-lt ltm rtm) (lamb-lt (ann-term1 ctx ltm)
143
:ttype (coprod so1 so1)))
144
((modulo ltm rtm) (let ((ant (ann-term1 ctx ltm)))
147
:ttype (ttype ant))))
148
((case-on on ltm rtm)
149
(let* ((ann-on (ann-term1 ctx on))
150
(type-of-on (ttype ann-on))
151
(ann-left (ann-term1 (cons (mcar type-of-on) ctx) ltm))
152
(ann-right (ann-term1 (cons (mcadr type-of-on) ctx) rtm)))
153
(if (typep type-of-on 'coprod)
154
(case-on ann-on ann-left ann-right :ttype (ttype ann-left))
155
(error "type of on not of coproduct type")))))))
157
;; Changes the stand in Geb term with exponential stand-ins
158
;; to one containing actual hom-objects
159
(defun fun-to-hom (t1)
160
"Given a [SUBSTOBJ][GEB.SPEC:SUBSTOBJ] whose subobjects might have a
161
[FUN-TYPE][class] occurence replaces all occurences of [FUN-TYPE][class] with a
162
suitable [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ], hence giving a pure
163
[SUBSTOBJ][GEB.SPEC:SUBSTOBJ]
166
LAMBDA> (fun-to-hom (fun-type geb-bool:bool geb-bool:bool))
167
(× (+ GEB-BOOL:FALSE GEB-BOOL:TRUE) (+ GEB-BOOL:FALSE GEB-BOOL:TRUE))
169
(cond ((typep t1 'prod) (prod (fun-to-hom (mcar t1))
170
(fun-to-hom (mcadr t1))))
171
((typep t1 'coprod) (coprod (fun-to-hom (mcar t1))
172
(fun-to-hom (mcadr t1))))
173
((typep t1 'fun-type) (so-hom-obj (fun-to-hom (mcar t1))
174
(fun-to-hom (mcadr t1))))
177
;; Changes all annotated terms' types to actual Geb objects
179
(defun ann-term2 (tterm)
180
"Given an [STLC][type] term with a [TTYPE][generic-function] accessor from
181
[ANN-TERM1][generic-function] - i.e. including possible [FUN-TYPE][class]
182
occurences - re-annotates the term and its subterms with actual
183
[SUBSTOBJ][GEB.SPEC:SUBSTOBJ] objects."
185
((absurd tcod term) (absurd (fun-to-hom tcod)
187
:ttype (fun-to-hom (ttype tterm))))
189
((right lty term) (right (fun-to-hom lty)
191
:ttype (fun-to-hom (ttype tterm))))
192
((left rty term) (left (fun-to-hom rty)
194
:ttype (fun-to-hom (ttype tterm))))
195
((case-on on ltm rtm) (case-on (ann-term2 on)
198
:ttype (fun-to-hom (ttype tterm))))
199
((pair ltm rtm) (pair (ann-term2 ltm)
201
:ttype (fun-to-hom (ttype tterm))))
202
((fst term) (fst (ann-term2 term)
203
:ttype (fun-to-hom (ttype tterm))))
204
((snd term) (snd (ann-term2 term)
205
:ttype (fun-to-hom (ttype tterm))))
206
((lamb tdom term) (lamb (mapcar #'fun-to-hom tdom)
208
:ttype (fun-to-hom (ttype tterm))))
209
((app fun term) (app (ann-term2 fun)
210
(mapcar #'ann-term2 term)
211
:ttype (fun-to-hom (ttype tterm))))
212
((index pos) (index pos
213
:ttype (fun-to-hom (ttype tterm))))
214
((err ttype) (err (fun-to-hom ttype)))
225
(defun annotated-term (ctx term)
226
"Given a context consisting of a list of [SUBSTOBJ][GEB.SPEC:SUBSTOBJ]
227
with occurences of [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ] replaced by
228
[FUN-TYPE][class] and an [STLC][type] term with similarly replaced occurences
229
of [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ], provides an [STLC][type] with all
230
subterms typed, i.e. providing the [TTYPE][generic-function] accessor,
231
which is a pure [SUBSTOBJ][GEB.SPEC:SUBSTOBJ]"
232
(ann-term2 (ann-term1 ctx term)))
235
;; Produces a type of a lambda term in a context
236
;; with a stand-in for the exponential object
238
(defun type-of-term-w-fun (ctx tterm)
239
"Given a context consisting of a list of [SUBSTOBJ][GEB.SPEC:SUBSTOBJ] with
240
occurences of [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ] replaced by [FUN-TYPE][class]
241
and an [STLC][type] term with similarly replaced occurences of
242
[SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ], gives out a type of the whole term with
243
occurences of [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ] replaced by [FUN-TYPE][class]."
244
(ttype (ann-term1 ctx tterm)))
248
(defun type-of-term (ctx tterm)
249
"Given a context consisting of a list of [SUBSTOBJ][GEB.SPEC:SUBSTOBJ] with
250
occurences of [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ] replaced by [FUN-TYPE][class]
251
and an [STLC][type] term with similarly replaced occurences of
252
[SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ], provides the type of the whole term,
253
which is a pure [SUBSTOBJ][type]."
254
(fun-to-hom (type-of-term-w-fun ctx tterm)))
256
;;Predicate checking that a term in a given context is well-typed
258
(defgeneric well-defp (ctx tterm)
260
"Given a context consisting of a list of [SUBSTOBJ][GEB.SPEC:SUBSTOBJ]
261
with occurences of [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ] replaced by
262
[FUN-TYPE][class] and an [STLC][type] term with similarly replaced
263
occurences of [SO-HOM-OBJ][GEB.COMMON:SO-HOM-OBJ], checks that the term
264
is well-defined in the context based on structural rules of simply
265
typed lambda calculus. returns the t if it is, otherwise returning
268
(defmethod well-defp (ctx (tterm <stlc>))
269
(labels ((check (tterm)
272
(and (check (term tterm))
273
(obj-equalp (ttype (term tterm)) so0)))
276
(obj-equalp (mcar (ttype tterm)) (ttype term))))
279
(obj-equalp (mcadr (ttype tterm)) (ttype term))))
285
(obj-equalp (ttype tterm) (mcar (ttype term)))))
288
(obj-equalp (ttype tterm) (mcadr (ttype term)))))
289
((case-on on ltm rtm)
293
(obj-equalp (ttype ltm) (ttype rtm))))
295
(let ((lambda-type (ttype tterm)))
297
(obj-equalp (mcar lambda-type) (reduce #'prod tdom))
298
(obj-equalp (mcadr lambda-type) (ttype term)))))
301
(check (reduce #'pair term :from-end t))
302
(typep (ttype fun) 'fun-type)
303
(obj-equalp (ttype fun)
304
(fun-type (reduce #'prod
305
(mapcar #'ttype term)
313
(obj-equalp (ttype (ltm tterm))
314
(ttype (rtm tterm))))
322
(let ((term (ignore-errors
323
(ann-term1 ctx tterm))))
324
(and term (check term)))))
326
(defun errorp (tterm)
327
"Evaluates to true iff the term has an error subterm."
328
(cond ((or (typep tterm 'index)
330
(typep tterm 'bit-choice))
332
((typep tterm 'err) t)
333
((typep tterm 'case-on) (or (errorp (on tterm))
335
(errorp (ltm tterm))))
336
((typep tterm 'pair) (or (errorp (ltm tterm))
337
(errorp (rtm tterm))))
338
((typep tterm 'app) (or (errorp (fun tterm))
341
(lambda (x) (errorp x))
343
((or (typep tterm 'plus)
346
(typep tterm 'divide)
347
(typep tterm 'lamb-eq)
348
(typep tterm 'lamb-lt)
349
(typep tterm 'modulo))
350
(or (errorp (ltm tterm))
351
(errorp (rtm tterm))))
352
(t (errorp (term tterm)))))
354
(defun dispatch (tterm)
355
"A dispatch refering the class of a term to its function"
369
(bit-choice #'bit-choice)
378
(defun dispatch-arith (tterm)
379
"A dispatch refering the class of an arithmetic term
380
to its corresponding operation"
390
(defun index-excess (tterm)
391
"Checks all indeces occuring in a term which will be substituted.
392
If position exceeds n, adds depth to the index. Necessary for
393
beta-substitution of indices which point outside of the app term"
394
(labels ((rec (n tterm)
396
(absurd (absurd (tcod tterm)
397
(rec n (term tterm))))
398
(left (left (rty tterm)
399
(rec n (term tterm))))
400
(right (right (lty tterm)
401
(rec n (term tterm))))
402
(case-on (case-on (rec n (on tterm))
403
(rec (1+ n) (ltm tterm))
404
(rec (1+ n) (rtm tterm))))
405
(fst (fst (rec n (term tterm))))
406
(snd (snd (rec n (term tterm))))
407
(lamb (lamb (tdom tterm)
408
(rec (1+ n) (term tterm))))
409
(app (app (rec n (fun tterm))
410
(list (rec n (car (term tterm))))))
411
(index (if (>= (pos tterm) n)
412
(index (1+ (pos tterm)))
426
(funcall (dispatch tterm)
428
(rec n (rtm tterm)))))))
431
(defun index-lack (n tterm)
432
"Checks if a term has made substitutions and decreases the index
434
(labels ((rec (n tterm)
435
(if (typep tterm 'list)
438
(absurd (absurd (tcod tterm)
439
(rec n (term tterm))))
440
(left (left (rty tterm)
441
(rec n (term tterm))))
442
(right (right (lty tterm)
443
(rec n (term tterm))))
444
(case-on (case-on (rec n (on tterm))
445
(rec (1+ n) (ltm tterm))
446
(rec (1+ n) (rtm tterm))))
447
(fst (fst (rec n (term tterm))))
448
(snd (snd (rec n (term tterm))))
449
(lamb (lamb (tdom tterm)
450
(rec (1+ n) (term tterm))))
451
(app (app (rec n (fun tterm))
452
(list (rec n (car (term tterm))))))
453
(index (if (> (pos tterm) n)
454
(index (1- (pos tterm)))
468
(funcall (dispatch tterm)
470
(rec n (rtm tterm))))))))
473
(defun delist (tterm)
474
"We mark substituted terms by listing them. This function recovers the car
476
(if (typep tterm 'list)
479
(absurd (absurd (tcod tterm)
480
(delist (term tterm))))
481
(left (left (rty tterm)
482
(delist (term tterm))))
483
(right (right (lty tterm)
484
(delist (term tterm))))
485
(case-on (case-on (delist (on tterm))
487
(delist (rtm tterm))))
488
(fst (fst (delist (term tterm))))
489
(snd (snd (delist (term tterm))))
490
(lamb (lamb (tdom tterm)
491
(delist (term tterm))))
492
(app (app (delist (fun tterm))
493
(list (delist (car (term tterm))))))
507
(funcall (dispatch tterm)
509
(delist (rtm tterm)))))))
511
(defun sub (ind term-to-replace sub-in)
512
"Substitutes the occurence of index (ind) inside of the top
513
subterms of sub-on by term-to-replace. We mark replaced terms by
516
(absurd (absurd (tcod sub-in) (sub ind
519
(left (left (rty sub-in) (sub ind
522
(right (right (lty sub-in) (sub ind
525
(case-on (case-on (sub ind
529
(index-excess term-to-replace)
532
(index-excess term-to-replace)
534
(fst (fst (substitute ind
537
(snd (snd (substitute ind
540
(lamb (lamb (tdom sub-in)
542
(index-excess term-to-replace)
544
(app (app (sub ind term-to-replace (fun sub-in))
545
(list (sub ind term-to-replace (car (term sub-in))))))
546
(index (if (= (pos sub-in) ind)
547
(list term-to-replace)
561
(funcall (dispatch sub-in)
562
(sub ind term-to-replace (ltm sub-in))
563
(sub ind term-to-replace (rtm sub-in))))))
565
(defun reducer (tterm)
566
"Reduces a given Lambda term by applying explict beta-reduction
567
when possible alongside arithmetic simplification. We assume that the
568
lambda and app terms are 1-argument"
570
(absurd (absurd (tcod tterm) (reducer (term tterm))))
571
(left (left (rty tterm) (reducer (term tterm))))
572
(right (right (lty tterm) (reducer (term tterm))))
573
(case-on (let ((on (on tterm))
576
(cond ((typep on 'left) (substitute-zero on ltm))
577
((typep on 'right) (substitute-zero on rtm))
578
(t (case-on (reducer on)
581
(pair (pair (reducer (ltm tterm))
582
(reducer (rtm tterm))))
583
(fst (let ((term (term tterm)))
584
(if (typep (reducer term) 'pair)
586
(fst (reducer term)))))
587
(snd (let ((term (term tterm)))
588
(if (typep (reducer term) 'pair)
590
(snd (reducer term)))))
591
(lamb (lamb (tdom tterm) (reducer (term tterm))))
593
(let ((fun (fun tterm))
594
(term (car (term tterm))))
595
(cond ((typep fun 'lamb)
596
(substitute-zero (reducer term) (reducer (term fun))))
597
((and (typep fun 'case-on)
598
(typep (ltm fun) 'lamb)
599
(typep (rtm fun) 'lamb))
600
(let ((irec (index-excess (reducer term))))
601
(flet ((zero-index (term)
602
(substitute-zero irec (reducer (term term)))))
603
(reducer (case-on (reducer (on fun))
604
(zero-index (ltm fun))
605
(zero-index (rtm fun)))))))
606
((and (typep fun 'case-on)
607
(typep (ltm fun) 'lamb)
608
(typep (rtm fun) 'case-on))
609
(reducer (case-on (reducer (on fun))
610
(substitute-zero (index-excess (reducer term))
611
(reducer (term (ltm fun))))
612
(reducer (app (rtm fun)
613
(list (index-excess term)))))))
614
((and (typep fun 'case-on)
615
(typep (ltm fun) 'lamb)
616
(typep (rtm fun) 'case-on))
617
(reducer (case-on (reducer (on fun))
618
(reducer (app (ltm fun)
619
(list (index-excess term))))
620
(substitute-zero (index-excess (reducer term))
621
(reducer (term (rtm fun)))))))
623
(err (mcadr (ttype fun))))
624
(t (app (reducer fun) (list (reducer term)))))))
627
(let ((ltm (ltm tterm))
629
(if (and (typep ltm 'bit-choice)
630
(typep rtm 'bit-choice))
631
(if (funcall (dispatch-arith tterm)
636
(funcall (dispatch tterm)
644
(let ((ltm (ltm tterm))
646
(if (and (typep ltm 'bit-choice)
647
(typep rtm 'bit-choice))
649
(funcall (dispatch-arith tterm)
652
(funcall (dispatch tterm)
661
(defun substitute-zero (replaced-term replacing-term)
662
"Substitutes the zero'th index, and properly marks it"
663
(delist (index-lack 0 (sub 0 replaced-term replacing-term))))