Skip to content

Commit fdb8f72

Browse files
authored
Create 2025-05-12-LambdaCalculus.md
1 parent 8a158eb commit fdb8f72

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

_posts/2025-05-12-LambdaCalculus.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
---
2+
layout: post
3+
title: Explore Lambda Calculus - Part I
4+
published: false
5+
---
6+
7+
# Simple Lambda Calculus interpreter
8+
9+
10+
## Porting FSharp code to OCaml
11+
12+
13+
14+
{% highlight ocaml%}
15+
16+
type arithmetic_fn = | Add | Sub | Mul | Div
17+
18+
module type ARITHMETIC_FN=
19+
sig
20+
type t = arithmetic_fn
21+
type a = int
22+
type b = int
23+
val apply : t -> a -> b -> a
24+
end
25+
26+
type comparison_fn =
27+
| Less
28+
| Equal
29+
| Greater
30+
31+
module type COMPARISON_FN=
32+
sig
33+
type t = comparison_fn
34+
type a = int
35+
type b = int
36+
val apply : t -> a -> b -> a
37+
end
38+
39+
40+
module Lang(ArithmeticType : ARITHMETIC_FN)
41+
(ComparisonType : COMPARISON_FN) = struct
42+
43+
module ArithmeticType = ArithmeticType
44+
module ComparisonType = ComparisonType
45+
type var_name = string
46+
type btype = int
47+
48+
49+
exception Type_error
50+
51+
52+
type builtin_fn =
53+
|Arithmetic of ArithmeticType.t * expr * expr
54+
|Comparison of ComparisonType.t * expr * expr
55+
and
56+
expr =
57+
| Var of var_name
58+
| Abs of var_name * expr
59+
| App of expr * expr
60+
| Lit of btype
61+
| Builtin of builtin_fn
62+
| Cond of expr * expr * expr
63+
64+
65+
type eval_error = WrongType of expr * string
66+
67+
exception EvalException of eval_error
68+
69+
end
70+
71+
module Language =
72+
Lang(struct
73+
type t = arithmetic_fn
74+
type a = int
75+
type b = int
76+
let apply fn a b : int =
77+
match fn with
78+
| Add -> a + b
79+
| Sub -> a - b
80+
| Mul -> a * b
81+
| Div -> a / b
82+
end)
83+
(struct
84+
type t = comparison_fn
85+
type a = int
86+
type b = int
87+
let apply fn a b : int =
88+
match fn with
89+
| Less -> if a < b then 1 else 0
90+
| Greater -> if a > b then 1 else 0
91+
| Equal -> if a = b then 1 else 0
92+
end)
93+
94+
95+
module Expr = struct
96+
include Language
97+
98+
let asInt = function
99+
| Lit btype -> btype
100+
| other -> raise( EvalException(WrongType( other, "int" )) )
101+
let asAbs = function
102+
| Abs (var, body ) -> var, body
103+
| other -> raise( EvalException(WrongType( other, "lambda" )) )
104+
105+
106+
let rec subst (replaceable : var_name ) (replaceWith : expr ) (expr : expr) =
107+
let substFn = subst replaceable replaceWith in
108+
match expr with
109+
| Lit _ -> expr
110+
| Builtin ( Arithmetic( fn, opA, opB ) ) ->
111+
Builtin ( Arithmetic( fn, substFn opA, substFn opB ) )
112+
| Builtin ( Comparison( fn, opA, opB ) ) ->
113+
Builtin ( Comparison( fn, substFn opA, substFn opB ) )
114+
| Cond (pred, trueBranch, falseBranch) ->
115+
Cond ( substFn pred, substFn trueBranch, substFn falseBranch)
116+
| App ( expr, arg ) -> App( substFn expr , substFn arg )
117+
| Var boundName -> if boundName = replaceable then replaceWith else expr
118+
| Abs (boundName, body ) -> if boundName = replaceable then expr else
119+
Abs( boundName, substFn body )
120+
121+
122+
and eval( expr : expr ) : expr =
123+
match expr with
124+
| Lit _ -> expr
125+
| Builtin ( Arithmetic( fn, opA, opB ) ) ->
126+
let valA = eval opA |> asInt in
127+
let valB = eval opB |> asInt in
128+
Lit ( ArithmeticType.apply fn valA valB)
129+
| Builtin ( Comparison( fn, opA, opB ) ) ->
130+
let lhs = eval opA |> asInt in
131+
let rhs = eval opB |> asInt in
132+
Lit (ComparisonType.apply fn lhs rhs )
133+
| Cond (pred, trueBranch, falseBranch) ->
134+
let valPred = eval pred |> asInt in
135+
if valPred <> 0 then eval trueBranch else eval falseBranch
136+
| Abs _ -> expr
137+
138+
| App( expr, arg ) ->
139+
let lambdaVar, lambdaBody = eval expr |> asAbs in
140+
subst lambdaVar arg lambdaBody |> eval
141+
142+
| Var _ -> failwith "Wrong evaluation "
143+
144+
end
145+
include Language
146+
let lit n = Lit n
147+
let incrFn = Abs ("x", Builtin( Arithmetic( Add, Var "x", lit 1 )))
148+
let incrApp n = App( incrFn, lit n )
149+
150+
let lazyFixpoint =
151+
let innerAbs =
152+
Abs(
153+
"x",
154+
App( Var "f", App( Var "x", Var "x" ) )) in
155+
Abs( "f", App ( innerAbs, innerAbs ))
156+
157+
let fibStep =
158+
let xMinus n = Builtin (Arithmetic( Sub, Var "x", lit n )) in
159+
let fb = Builtin( Arithmetic( Add, App( Var "f", xMinus 1 ), App( Var "f", xMinus 2 ) ) ) in
160+
Abs( "f",
161+
Abs(
162+
"x",
163+
Cond(
164+
Builtin( Comparison( Less, Var "x", lit 2 ) ),
165+
lit 1,
166+
fb
167+
)
168+
)
169+
)
170+
171+
let fib( n : int ) =
172+
let fn = App( lazyFixpoint, fibStep ) in
173+
App( fn, lit n )
174+
175+
176+
{% endhighlight%}

0 commit comments

Comments
 (0)