lean4-htt/tests/lean/run/doNotation3.lean
Leonardo de Moura 483f32edd8 feat: in pure code, do use assume Id monad at do notation
This feature produced counterintuitive behavior and confused users.
See discussion at #770.

As pointed out by @tydeu, it is not too much work to write `Id.run <|`
before the `do` when we want to use the `do` notation in pure code.

closes #770
2021-12-10 12:55:14 -08:00

84 lines
2.6 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

theorem zero_lt_of_lt : {a b : Nat} → a < b → 0 < b
| 0, _, h => h
| a+1, b, h =>
have : a < b := Nat.lt_trans (Nat.lt_succ_self _) h
zero_lt_of_lt this
def fold {m α β} [Monad m] (as : Array α) (b : β) (f : α → β → m β) : m β := do
let rec loop : (i : Nat) → i ≤ as.size → β → m β
| 0, h, b => b
| i+1, h, b => do
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
have : as.size - 1 < as.size := Nat.sub_lt (zero_lt_of_lt h') (by decide)
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
let b ← f (as.get ⟨as.size - 1 - i, this⟩) b
loop i (Nat.le_of_lt h') b
loop as.size (Nat.le_refl _) b
#eval Id.run $ fold #[1, 2, 3, 4] 0 (pure $ · + ·)
theorem ex : (Id.run $ fold #[1, 2, 3, 4] 0 (pure $ · + ·)) = 10 :=
rfl
def fold2 {m α β} [Monad m] (as : Array α) (b : β) (f : α → β → m β) : m β :=
let rec loop (i : Nat) (h : i ≤ as.size) (b : β) : m β := do
match i, h with
| 0, h => return b
| i+1, h =>
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
have : as.size - 1 < as.size := Nat.sub_lt (zero_lt_of_lt h') (by decide)
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
let b ← f (as.get ⟨as.size - 1 - i, this⟩) b
loop i (Nat.le_of_lt h') b
loop as.size (Nat.le_refl _) b
def f (x : Nat) (ref : IO.Ref Nat) : IO Nat := do
let mut x := x
if x == 0 then
x ← ref.get
IO.println x
return x + 1
def fTest : IO Unit := do
unless (← f 0 (← IO.mkRef 10)) == 11 do throw $ IO.userError "unexpected"
unless (← f 1 (← IO.mkRef 10)) == 2 do throw $ IO.userError "unexpected"
def g (x y : Nat) (ref : IO.Ref (Nat × Nat)) : IO (Nat × Nat) := do
let mut (x, y) := (x, y)
if x == 0 then
(x, y) ← ref.get
IO.println ("x: " ++ toString x ++ ", y: " ++ toString y)
return (x, y)
def gTest : IO Unit := do
unless (← g 2 1 (← IO.mkRef (10, 20))) == (2, 1) do throw $ IO.userError "unexpected"
unless (← g 0 1 (← IO.mkRef (10, 20))) == (10, 20) do throw $ IO.userError "unexpected"
return ()
#eval gTest
macro "ret!" x:term : doElem => `(return $x)
def f1 (x : Nat) : Nat := Id.run <| do
let mut x := x
if x == 0 then
ret! 100
x := x + 1
ret! x
theorem ex1 : f1 0 = 100 := rfl
theorem ex2 : f1 1 = 2 := rfl
theorem ex3 : f1 3 = 4 := rfl
syntax "inc!" ident : doElem
macro_rules
| `(doElem| inc! $x) => `(doElem| $x:ident := $x + 1)
def f2 (x : Nat) : Nat := Id.run <| do
let mut x := x
inc! x
ret! x
theorem ex4 : f2 0 = 1 := rfl
theorem ex5 : f2 3 = 4 := rfl