-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplt-redex.rkt
187 lines (144 loc) · 4.84 KB
/
plt-redex.rkt
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
#|
PLT Redex demo by Yufei Cai
Date: 15.04.13
Place: 05D09 SR V
This file
https://github.com/yfcai/demos/blob/master/plt-redex.rkt
PLT Redex homepage and examples
http://redex.racket-lang.org
PLT Redex manual
http://docs.racket-lang.org/redex/The_Redex_Reference.html
This file follows ideas in the following two:
https://github.com/klauso/PLT2012/blob/master/lecturenotes/02-ae.scala
https://github.com/klauso/PLT2012/blob/master/lecturenotes/05-fae.scala
|#
#lang racket
(require redex)
;; 02-ae.scala:20
;; (define-language lang-name
;; non-terminal-def ...)
(define-language AE
;; Exp ::= Num | Add | Mul | Id
(Exp Num Add Mul Id)
;; Num ::= ... | -2 | -1 | 0 | 1 | 2 | ...
(Num integer)
;; Add ::= Exp + Exp
(Add (Exp + Exp))
;; Mul ::= Exp * Exp
(Mul (Exp * Exp))
;; Id ::= a | b | ... | ab | ac | ...
(Id (variable-except + *)))
(define malformed '(+ (* x 2) (+ y y)))
(define test0 '((x * 2) + (y + y)))
(define test1 '((9 * 2) + (12 + 12)))
;; (redex-match lang pattern any)
;; (test-equal e1 e2)
(test-equal (redex-match AE Exp malformed) #f)
;; (test-predicate p? e)
(test-predicate identity (redex-match AE Exp test0))
(test-predicate identity (redex-match AE Exp test1))
;; Evaluation context is a built-in concept in Redex.
;; We use it to encode congruence reduction rules here.
;; (define-extended-language extended-lang base-lang
;; non-terminal-def ...)
(define-extended-language eval-ctx AE
(E hole
(E + Exp) (Exp + E)
(E * Exp) (Exp * E)))
(define arith
(reduction-relation
eval-ctx ; AE
(reduce (Num_1 + Num_2) ,(+ (term Num_1) (term Num_2)) "δ+")
(reduce (Num_1 * Num_2) ,(* (term Num_1) (term Num_2)) "δ*")
with
[(--> (in-hole E e1) (in-hole E e2)) (reduce e1 e2)]))
;; Opens a GUI to show all possible reductions from a term
;; (traces arith test1)
;; (traces arith test0)
;; It is awkward to thread an environment down to evaluate open
;; terms such as test0. So instead of
;;
;; 02-ae.scala:55
;;
;; we will proceed directly to a full-blown λ-calculus to deal
;; with names:
;;
;; 05-fae.scala:53
(define-extended-language FAE AE
;; Syntax
(Exp Num Add Mul Id Fun App)
(Id (variable-except + * λ))
(Fun (λ Id Exp))
(App (Exp Exp))
;; Evaluation context
(E hole
(E + Exp) (Exp + E)
(Exp * E) (E * Exp)
(E Exp) (Exp E)))
;; How should we write `test0 with x = 9 and y = 12`?
;;
;; (((λ x (λ y ,test0)) 9) 12)
;;
;; This is complicated. Often it is error-prone to write
;; expressions in a concrete syntax with a simple definition.
;; Syntactic sugars simplify terms without complicating their
;; reduction rules.
;; (define-metafunction language
;; metafunction-contract
;; [(name pattern ...) term metafunction-extras ...]
;; ...)
;; Syntactic sugar for multivariate lambda abstraction
;; (λ* (x y) Exp) ::= (λ x (λ y Exp))
(define-metafunction FAE
λ* : (Id ...) Exp -> Exp
[(λ* (Id_0 Id_1 ...) Exp) (λ Id_0 (λ* (Id_1 ...) Exp))]
[(λ* () Exp) Exp])
(test-equal (term (λ* (x y) z)) '(λ x (λ y z)))
;; Syntactic sugar for multivariate application
;; (@ e1 e2 e3) ::= ((e1 e2) e3)
(define-metafunction FAE
@ : Exp ... -> Exp
[(@ Exp_0 Exp_1) (Exp_0 Exp_1)]
[(@ Exp_0 Exp_1 Exp_2 ...) (@ (Exp_0 Exp_1) Exp_2 ...)])
(test-equal (term (@ x y z)) '((x y) z))
(define test2 (term (@ (λ* (x y) ,test0) 9 12)))
(test-equal test2 '(((λ x (λ y ((x * 2) + (y + y)))) 9 ) 12))
;; Evaluation by substitution
;;
;; 05-fae.scala:177
(define βδ
(extend-reduction-relation
arith FAE
(reduce ((λ Id Exp_0) Exp_1) (subst Id Exp_1 Exp_0) "β")
with
[(--> (in-hole E e1) (in-hole E e2)) (reduce e1 e2)]))
;; (traces βδ '((λ x x) (3 + 5)))
(define-metafunction FAE
subst : Id Exp any -> any
[(subst Id Exp Id) Exp]
[(subst Id Exp Id_1) Id_1]
[(subst Id Exp (λ Id Exp_0)) (λ Id Exp_0)]
[(subst Id Exp (λ Id_0 Exp_0))
(λ Id_fresh (subst Id Exp (subst Id_0 Id_fresh Exp_0)))
(where Id_fresh ,(variable-not-in (term (Id Exp Exp_0))
(term Id_0)))]
;; Congruence on App, Add, Mul
[(subst Id Exp (any ...)) ((subst Id Exp any) ...)]
[(subst Id Exp any) any])
;; (traces βδ '((λ x x) (3 + 5)))
;; (traces βδ test2)
(test-predicate (λ (results) (member 42 results))
(apply-reduction-relation* βδ test2))
;; Redex supports automatic attempts at refuting properties of a language.
;; For example: Does all FAE expressions evaluate to a number?
;; (redex-check language pattern property-expr kw-arg ...)
(redex-check
FAE Exp
(not (empty? (filter number? (apply-reduction-relation* βδ (term Exp))))))
;; Let's try to refute Church-Rosser property on terms that evaluate to
;; a number.
(define (CR/Num? e)
(>= 1 (length (remove-duplicates
(filter number?
(apply-reduction-relation* βδ e))))))
(redex-check FAE Exp (CR/Num? (term Exp)))