-
Notifications
You must be signed in to change notification settings - Fork 0
/
monad.lean4
186 lines (150 loc) · 4.03 KB
/
monad.lean4
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
import Std.Data.AssocList
import Mathlib.Init.Data.Nat.Lemmas
open Std
abbrev Var := String
class Imperative (m) extends Monad m where
load : Var → m Nat
store : Var → Nat → m Unit
prefix:100 "⋆" => Imperative.load
infix:1 " ≔ " => Imperative.store
instance [Imperative m] : Coe Var (m Nat) where
coe := Imperative.load
/-
abbrev Imp := StateT (AssocList Var Nat) OptionM
instance : Imperative Imp where
load x := get >>= StateT.lift ∘ AssocList.find? x
store x n := modify λ s => s.insert x n
def Imp.sim (m : Imp α) : Option α :=
(m ∅).map Prod.fst
def Imp.loop (c : Imp Bool) : Nat → Imp Unit
| 0 => StateT.lift none
| f + 1 => do if ← c then return () else loop c f
def Imp.while (f : Nat) (cond : Imp Bool) (body : Imp Unit) : Imp Unit :=
loop (do if ← cond then do body; return false else return true) (f + 1)
/-
class imperative m extends monad m :=
(load : var → m ℕ)
(store : var → ℕ → m unit)
(loop : m bool → ℕ → m unit)
def imperative.while {m} [imperative m] (f : ℕ) (cond : m bool) (body : m unit) : m unit :=
imperative.loop (do b ← cond, if b then do body, return ff else return tt) (f + 1)
open imperative (while) imp (sim)
-/
open Imp (sim)
#eval sim do
"x" ≔ 10
"y" ≔ 0
Imp.while (←"x") (return (←"x") > 0) (do
"y" ≔ (←"x") + (←"y")
"x" ≔ (←"x") - 1
)
⋆"y"
-/
/-
abbrev Imp := StateT (Nat × AssocList Var Nat) OptionM
instance : Imperative Imp where
load x := get >>= StateT.lift ∘ AssocList.find? x ∘ Prod.snd
store x n := modify <| Prod.map id λ s => s.insert x n
def Imp.sim (f : Nat) (m : Imp α) : Option α :=
(m (f, ∅)).map Prod.fst
def Imp.while' (cond : Imp Bool) (body : Imp Unit) : Nat → AssocList Var Nat → OptionM (Unit × Nat × AssocList Var Nat)
| 0, _ => none
| f + 1, s => do
let (c, s) ← cond (f + 1, s)
if c
then do
let ((), (_, s)) ← body s
while' cond body f s
else some ((), s)
def Imp.while (cond : Imp Bool) (body : Imp Unit) : Imp Unit :=
λ s => while' cond body s.fst s.snd
open Imp (sim)
/-
int x = 10;
int y = 0;
while (x > 0) {
y = x + y;
x = x - 1;
}
return y;
-/
#eval sim 11 do
"x" ≔ 10
"y" ≔ 0
Imp.while (return (←"x") > 0) (do
"y" ≔ (←"x") + (←"y")
"x" ≔ (←"x") - 1
)
⋆"y"
-/
abbrev Imp := StateT (AssocList Var Nat) OptionM
instance : Imperative Imp where
load x := get >>= StateT.lift ∘ AssocList.find? x
store x n := modify λ s => s.insert x n
def Imp.sim (m : Imp α) : Option α :=
(m ∅).map Prod.fst
open Imp (sim)
#eval sim do
"x" ≔ 10
"y" ≔ 0
while (←"x") > 0 do
"y" ≔ (←"x") + (←"y")
"x" ≔ (←"x") - 1
⋆"y"
def sqrt : Nat → Nat
| 0 => 0
| 1 => 1
| (x + 2) => let h := Nat.div_lt_self; let y := sqrt ((x + 2) / 2); if (y + y + 1) * (y + y + 1) ≤ x + 2 then y + y + 1 else y + y
termination_by _ x => x
theorem le_sub_of_add_le_left {x y : Nat} : {z : Nat} → x + y ≤ z → y ≤ z - x
| _, Nat.le.refl => Nat.le_of_eq <| Eq.symm <| Nat.add_sub_self_left _ _
| _, Nat.le.step h => let that := le_sub_of_add_le_left h; sorry
def sqrt' x lo hi :=
if h : lo + 1 < hi
then
let mid := lo + (hi - lo) / 2;
-- let hl : lo < mid := by { 2 ≤ hi - lo };
if mid > x / mid
then sqrt' x lo mid
else if mid < x / mid
then sqrt' x mid hi
else mid
else lo
def sqrt : Nat → Nat
| 0 => 0
| 1 => 1
| x => sqrt' x 0 x
def sqrt x := Id.run do
if x < 2 then return x
let mut lo := 0
let mut hi := x
while lo + 1 < hi do
let mid := lo + (hi - lo) / 2
if mid > x / mid then
hi := mid
else if mid < x / mid then
lo := mid
else return mid
return lo
/-
int sqrt(int x) {
if (x < 2) return x;
int lo = 0;
int hi = x;
while (lo + 1 < hi) {
int mid = lo + (hi - lo) / 2;
if (mid > x / mid) hi = mid;
else if (mid < x / mid) lo = mid;
else return mid;
}
return lo;
}
-/
/-
def bar := Id.run do
let mut x := 0
while x < 10 do
x := x + 1
return x
#eval bar
-/