After this commit, we have to use an explicit `discard` in code such as ``` def g (x : Nat) : IO Nat := ... def f (x : Nat) : IO Unit := do discard <| g x -- type error without the `discard` IO.println x ``` Motivation: prevent users from making mistakes such as ``` def f (xs : Array Nat) : IO Unit := do xs.set! 0 1 IO.println xs ``` when they meant to write ``` def f (xs : Array Nat) : IO Unit := do let xs := xs.set! 0 1 IO.println xs ```
99 lines
2.7 KiB
Text
99 lines
2.7 KiB
Text
/- Benchmark for new code generator -/
|
|
import Init.System.IO
|
|
|
|
|
|
inductive Expr
|
|
| Val : Int → Expr
|
|
| Var : String → Expr
|
|
| Add : Expr → Expr → Expr
|
|
| Mul : Expr → Expr → Expr
|
|
| Pow : Expr → Expr → Expr
|
|
| Ln : Expr → Expr
|
|
|
|
namespace Expr
|
|
|
|
unsafe def pown : Int → Int → Int
|
|
| a, 0 => 1
|
|
| a, 1 => a
|
|
| a, n =>
|
|
let b := pown a (n / 2);
|
|
b * b * (if n % 2 = 0 then 1 else a)
|
|
|
|
unsafe def add : Expr → Expr → Expr
|
|
| Val n, Val m => Val (n + m)
|
|
| Val 0, f => f
|
|
| f, Val 0 => f
|
|
| f, Val n => add (Val n) f
|
|
| Val n, Add (Val m) f => add (Val (n+m)) f
|
|
| f, Add (Val n) g => add (Val n) (add f g)
|
|
| Add f g, h => add f (add g h)
|
|
| f, g => Add f g
|
|
|
|
unsafe def mul : Expr → Expr → Expr
|
|
| Val n, Val m => Val (n*m)
|
|
| Val 0, _ => Val 0
|
|
| _, Val 0 => Val 0
|
|
| Val 1, f => f
|
|
| f, Val 1 => f
|
|
| f, Val n => mul (Val n) f
|
|
| Val n, Mul (Val m) f => mul (Val (n*m)) f
|
|
| f, Mul (Val n) g => mul (Val n) (mul f g)
|
|
| Mul f g, h => mul f (mul g h)
|
|
| f, g => Mul f g
|
|
|
|
unsafe def pow : Expr → Expr → Expr
|
|
| Val m, Val n => Val (pown m n)
|
|
| _, Val 0 => Val 1
|
|
| f, Val 1 => f
|
|
| Val 0, _ => Val 0
|
|
| f, g => Pow f g
|
|
|
|
def ln : Expr → Expr
|
|
| Val 1 => Val 0
|
|
| f => Ln f
|
|
|
|
unsafe def d (x : String) : Expr → Expr
|
|
| Val _ => Val 0
|
|
| Var y => if x = y then Val 1 else Val 0
|
|
| Add f g => add (d x f) (d x g)
|
|
| Mul f g => add (mul f (d x g)) (mul g (d x f))
|
|
| Pow f g => mul (pow f g) (add (mul (mul g (d x f)) (pow f (Val (0 - 1)))) (mul (ln f) (d x g)))
|
|
| Ln f => mul (d x f) (pow f (Val (0 - 1)))
|
|
|
|
partial def count : Expr → Nat
|
|
| Val _ => 1
|
|
| Var _ => 1
|
|
| Add f g => count f + count g
|
|
| Mul f g => count f + count g
|
|
| Pow f g => count f + count g
|
|
| Ln f => count f
|
|
|
|
partial def Expr.toString : Expr → String
|
|
| Val n => ToString.toString n
|
|
| Var x => x
|
|
| Add f g => "(" ++ toString f ++ " + " ++ toString g ++ ")"
|
|
| Mul f g => "(" ++ toString f ++ " * " ++ toString g ++ ")"
|
|
| Pow f g => "(" ++ toString f ++ " ^ " ++ toString g ++ ")"
|
|
| Ln f => "ln(" ++ toString f ++ ")"
|
|
|
|
instance : ToString Expr :=
|
|
⟨Expr.toString⟩
|
|
|
|
unsafe def nest (f : Expr → IO Expr) : Nat → Expr → IO Expr
|
|
| 0, x => pure x
|
|
| n+1, x => f x >>= nest f n
|
|
|
|
unsafe def deriv (f : Expr) : IO Expr :=
|
|
do
|
|
let d := d "x" f;
|
|
IO.print "count: ";
|
|
IO.println (count f);
|
|
pure d
|
|
|
|
end Expr
|
|
|
|
unsafe def main : IO Unit :=
|
|
do let x := Expr.Var "x";
|
|
let f := Expr.pow x x;
|
|
discard $ Expr.nest Expr.deriv 9 f;
|
|
pure ()
|