-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbeta.ml
More file actions
389 lines (360 loc) · 12.1 KB
/
Copy pathbeta.ml
File metadata and controls
389 lines (360 loc) · 12.1 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
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
type char_type = LPAREN | RPAREN | LAMBDA | DOT | OTHER
type stream_type = STRING | CHANNEL
type lambda_v = string list
type tree = App of lambda_v | Lambda of lambda_v * tree list
let channel = open_in "/home/sode/prog/ocaml/lambda.lm"
let token_buf = Buffer.create 64
(* utilities *)
let get_l (a, b) = a
let get_r (a, b) = b
let rec each f e = fun x ->
match x with
[] -> e
| x::rest -> (
f x;
each f e rest
)
let rec contain list n =
match list with
x::rest ->
if x = n then true
else contain rest n
| [] -> false
let empty lambda =
match lambda with
App([]) -> true
| Lambda([], []) -> true
| _ -> false
let default_indent = " "
let rec show_list_native list =
match list with
[] -> ()
| x::rest ->
print_string (x ^ " ");
show_list_native (rest)
let rec show_lm_native lm indent =
match lm with
App(l) ->
print_string (indent ^ "App:");
show_list_native l;
print_string "\n"
| Lambda(l, list) ->
print_string (indent ^ "Lambda \n");
print_string (indent ^ " Variables:");
show_list_native l;
print_string "\n";
each (fun x -> show_lm_native x (indent ^ default_indent)) () list
let rec show_list list =
match list with
[] -> ()
| "paren"::rest -> show_list rest
| x::rest ->
print_string (x ^ " ");
show_list (rest)
let rec show_lm lm indent =
match lm with
App(l) ->
show_list l;
| Lambda(l, list) ->
match l with
[] ->
each (fun x -> show_lm x (indent ^ default_indent)) () list
| ["paren"] -> (
print_string "(";
each (fun x -> show_lm x (indent ^ default_indent)) () list;
print_string ")"
)
| _ -> (
print_string "(\\";
show_list l;
print_string ". ";
each (fun x -> show_lm x (indent ^ default_indent)) () list;
print_string ")"
)
let get_v_lm lm =
match lm with
Lambda(v, l) -> v
| App(v) -> [""]
let get_children_lm lm =
match lm with
Lambda(v, l) -> l
| App(v) -> []
let add_lm_list_pre lm new_lm =
if not(empty new_lm) then
match lm with
Lambda([], []) -> new_lm
| Lambda(l, r) -> Lambda(l, [new_lm]@r)
| _ -> lm
else
lm
let add_variable_list_pre x value =
match x with
Lambda(l, r) -> Lambda(value::l, r)
| _ -> x
let add_lm_list lm new_lm =
if not(empty new_lm) then
match lm with
Lambda([], []) -> new_lm
| Lambda(l, r) -> Lambda(l, r@[new_lm])
| _ -> lm
else
lm
let add_variable_list lm value =
match lm with
Lambda(l, r) -> Lambda(l@[value], r)
| _ -> lm
let rec reduce_paren lm =
let rec reduce_paren_list lmlist =
match lmlist with
[] -> lmlist
| lm1::lmlist1 ->
(reduce_paren lm1)::(reduce_paren_list lmlist1)
in
match lm with
App(v) -> lm
| Lambda(["paren"], lmlist') -> (
match lmlist' with
[Lambda(["paren"], lmlist'')] ->
Lambda(["paren"], (reduce_paren_list lmlist''))
| [Lambda(vlist, lmlist''')] ->
Lambda(vlist, (reduce_paren_list lmlist'''))
| _ ->
Lambda(["paren"], (reduce_paren_list lmlist'))
)
| Lambda(vlist, lmlist') ->
Lambda(vlist, (reduce_paren_list lmlist'))
(* get token from lambda string *)
let check_type str =
match str with
"(" -> LPAREN
| ")" -> RPAREN
| "\\" -> LAMBDA
| "." -> DOT
| _ -> OTHER
let get_tokens in_str stream_type =
let get_a_char idx =
if stream_type = STRING then
in_str.[idx]
else
input_char channel
in
let add_token token_buf token tokens =
if Buffer.length token_buf != 0 then (
Buffer.clear token_buf;
token::tokens
) else (
tokens
)
in
let rec get_char in_token tokens idx =
try
let c = get_a_char idx in
match check_type (String.make 1 c) with
LPAREN|RPAREN|LAMBDA|DOT ->
let token = Buffer.contents token_buf in
get_char false ((String.make 1 c)::(add_token token_buf token tokens)) (idx + 1)
| OTHER ->
match c with
'\r' | '\n' | '\t' | ' ' ->
let token = Buffer.contents token_buf in
get_char false (add_token token_buf token tokens) (idx + 1)
| _ ->
if in_token then (
Buffer.add_char token_buf c;
get_char false ((Buffer.contents token_buf)::tokens) (idx + 1)
) else (
Buffer.add_char token_buf c;
get_char true tokens (idx + 1)
)
with
End_of_file -> tokens
| Invalid_argument in_str -> tokens
in
get_char false [] 0
(* parse. create Lambda tree *)
let rec parse tokens lm cur_lm is_lambda =
match tokens with
[] -> (
match cur_lm with
Lambda([], []) -> (lm, [])
| App(a) -> ((add_lm_list lm cur_lm), [])
| _ -> (lm, [])
)
| token::rest ->
match check_type token with
LPAREN ->
let (lm', next) = parse rest (Lambda([], [])) (Lambda(["paren"], [])) false in
parse next (add_lm_list (add_lm_list lm cur_lm) lm') (Lambda([], [])) false
| LAMBDA ->
parse rest lm cur_lm true
| DOT ->
parse rest lm cur_lm false
| RPAREN ->
((add_lm_list lm cur_lm), rest)
| OTHER ->
if is_lambda then
parse rest lm (add_variable_list cur_lm token) is_lambda
else
parse rest lm (add_lm_list cur_lm (App([token]))) is_lambda
(* Alpha Conversion *)
let rec get_replaced_v v depth =
if depth = 0 then v
else get_replaced_v (v ^ "0") (depth - 1)
let rec convert_vlist list x replace =
match list with
[] -> []
| y::rest ->
if x == y then replace::rest
else y::(convert_vlist rest x replace)
let rec alpha_convert x lmlist depth do_replace =
let replace_lm src replace lm depth =
match lm with
App(vlist) ->
if contain vlist src then
(App(convert_vlist vlist src replace), true)
else
(lm, false)
| Lambda(vlist, lmlist') ->
let (lmlist'', do_replace'') = (alpha_convert x lmlist' (depth + 1) do_replace) in
if do_replace'' then
(Lambda((convert_vlist vlist x (get_replaced_v src depth)), lmlist''), true)
else
(Lambda(vlist, lmlist''), false)
in
match lmlist with
[] -> ([], do_replace)
| lm::lmlist_rest ->
let replace = get_replaced_v x depth in
let (lm', do_replace') = replace_lm x replace lm depth in
if do_replace then
(lm'::(get_l(alpha_convert x lmlist_rest depth do_replace)), true)
else
let (lmlist', do_replace'') = (alpha_convert x lmlist_rest depth do_replace) in
(lm::lmlist', do_replace'')
let rec alpha = fun lm ->
match lm with
App(v) -> lm
| Lambda(vlist, lmlist) ->
match vlist with
["paren"]|[] ->
print_endline "alpha1";
each (fun x -> alpha x) (Lambda([],[])) lmlist
| x::vlist_rest ->
print_endline "alpha2";
let (lmlist', do_replace) = alpha_convert x lmlist 0 false in
if do_replace then (
print_endline "alpha2 suc";
Lambda(vlist, lmlist')
) else (
add_variable_list_pre (alpha (Lambda(vlist_rest, lmlist))) x
)
(* Beta Reduction *)
let rec beta_reduction = fun lm ->
let rec trans_lms lmlist x lm do_trans = (* lmlist u App:f do_trans *)
match lmlist with
[] -> ([], do_trans)
| lm'::rest ->
match lm' with
App(vlist) ->
if (contain vlist x) then (
let (lmlist1, do_trans1) = (trans_lms rest x lm true) in
((lm::lmlist1), true)
) else (
let (lmlist1, do_trans1) = (trans_lms rest x lm do_trans) in
(lm'::lmlist1, true)
)
| Lambda(l, r) ->
if (contain l x) then (* for alpha conversion *) (
(lmlist, do_trans)
)
else
let (lmlist1, do_trans1) = (trans_lms r x lm do_trans) in
let (lmlist2, do_trans2) = (trans_lms rest x lm do_trans) in
(Lambda(l, lmlist1)::lmlist2, (do_trans1 || do_trans2))
in
let rec trans_lm lm1 lm2 do_trans =
let rec trans_lmlist lmlist lm2 do_trans =
match lmlist with
[] -> (lmlist, false)
| lm::rest ->
let (lm', do_trans') = trans_lm lm lm2 do_trans in
let (lmlist', do_trans'') = trans_lmlist rest lm2 do_trans in
(lm'::lmlist', (do_trans'||do_trans''))
in
match lm1 with
App(vlist) -> (lm1, false)
| Lambda(vlist, lmlist) ->
match vlist with
[] -> (lm1, false)
| ["paren"] ->
let (lm'', do_trans'') = beta_reduction lm1 in (*trans_lmlist lmlist lm2 do_trans in*)
if do_trans'' then
(Lambda(["paren"], lm''::lm2::[]), true)
else
let (lmlist', do_trans''') = trans_lmlist lmlist lm2 do_trans in
if do_trans''' then
(Lambda(["paren"], lmlist'), true)
else
(lm1, false)
| [v1] ->
let (lmlist', do_trans') = trans_lms lmlist v1 lm2 false in
if do_trans' then
(Lambda(["paren"], lmlist'), true)
else
(lm1, false)
| "paren"::v2::rest ->
let (lmlist', do_trans') = trans_lms lmlist v2 lm2 false in
if do_trans' then
(Lambda("paren"::rest, lmlist'), true)
else
(lm1, false)
| v1::rest ->
let (lmlist', do_trans') = trans_lms lmlist v1 lm2 false in
if do_trans' then
(Lambda(rest, lmlist'), true)
else
(lm1, false)
in
match lm with
App(vlist) -> (lm, false)
| Lambda([], []) -> (lm, false)
| Lambda(vlist, lmlist) ->
match lmlist with
[] -> (lm, false)
| [lm'] ->
let (lm', do_trans') = beta_reduction lm' in
if do_trans' then
(Lambda(vlist, [lm']), true)
else
(lm, false)
| lm1::lm2::rest ->
let (lm'', do_trans) = trans_lm lm1 lm2 false in
let lmlist' =
if (get_v_lm lm'') = ["paren"] then (
get_children_lm lm''
) else
[lm'']
in
if do_trans then
(Lambda(vlist, lmlist'@rest), true)
else
let (lm1', do_trans') = beta_reduction lm1 in
if do_trans' then
(Lambda(vlist, lm1'::lm2::rest), true)
else
let (lm''', do_trans'') = beta_reduction (Lambda(vlist, lm2::rest)) in
if do_trans'' then
(Lambda(vlist, lm1::(get_children_lm lm''')), true)
else
(lm, false)
let rec beta lm do_trans do_show_tree =
let (lm', do_trans') = (beta_reduction lm) in
if not do_show_tree then (
show_lm lm' default_indent;
print_endline "";
);
if do_trans' then (
beta (reduce_paren lm') do_trans' do_show_tree
)
else
(lm', false)