This refactors and improves the `#eval` command, introducing some new
features.
* Now evaluated results can be represented using `ToExpr` and pretty
printing. This means **hoverable output**. If `ToExpr` fails, it then
tries `Repr` and then `ToString`. The `eval.pp` option controls whether
or not to try `ToExpr`.
* There is now **auto-derivation** of `Repr` instances, enabled with the
`pp.derive.repr` option (default to **true**). For example:
```lean
inductive Baz
| a | b
#eval Baz.a
-- Baz.a
```
It simply does `deriving instance Repr for Baz` when there's no way to
represent `Baz`. If core Lean gets `ToExpr` derive handlers, they could
be used here as well.
* The option `eval.type` controls whether or not to include the type in
the output. For now the default is false.
* Now things like `#eval do return 2` work. It tries using
`CommandElabM`, `TermElabM`, or `IO` when the monad is unknown.
* Now there is no longer `Lean.Eval` or `Lean.MetaEval`. These each used
to be responsible for both adapting monads and printing results. The
concerns have been split into two. (1) The `MonadEval` class is
responsible for adapting monads for evaluation (it is similar to
`MonadLift`, but instances are allowed to use default data when
initializing state) and (2) finding a way to represent results is
handled separately.
* Error messages about failed instance synthesis are now more precise.
Once it detects that a `MonadEval` class applies, then the error message
will be specific about missing `ToExpr`/`Repr`/`ToString` instances.
* Fixes a bug where `Repr`/`ToString` instances can't be found by
unfolding types "under the monad". For example, this works now:
```lean
def Foo := List Nat
def Foo.mk (l : List Nat) : Foo := l
#eval show Lean.CoreM Foo from do return Foo.mk [1,2,3]
```
* Elaboration errors now abort evaluation. This eliminates some
not-so-relevant error messages.
* Now evaluating a value of type `m Unit` never prints a blank message.
* Fixes bugs where evaluating `MetaM` and `CoreM` wouldn't collect log
messages.
The `run_cmd`, `run_elab`, and `run_meta` commands are now frontends for
`#eval`.
158 lines
3.2 KiB
Text
158 lines
3.2 KiB
Text
open Lean
|
||
|
||
def f : IO Nat :=
|
||
pure 0
|
||
|
||
def g (x : Nat) : IO Nat :=
|
||
pure (x + 1)
|
||
|
||
def g1 {α : Type} (x : α) : IO (α × α) :=
|
||
pure (x, x)
|
||
|
||
def g2 (p : Nat × Nat) : Nat :=
|
||
p.1
|
||
|
||
-- set_option trace.Elab.definition true
|
||
|
||
def h (x : Nat) : StateT Nat IO Nat := do
|
||
let s ← get
|
||
let a ← f -- liftM inserted here
|
||
let b ← g1 1 -- liftM inserted here
|
||
let x := g2 b
|
||
IO.println b
|
||
pure (s+a)
|
||
|
||
def myPrint {α} [ToString α] (a : α) : IO Unit :=
|
||
IO.println s!">> {a}"
|
||
|
||
def h₂ (x : Nat) : StateT Nat IO Nat := do
|
||
let a ← h 1; -- liftM inserted here
|
||
IO.println x
|
||
let b ← g1 a -- liftM inserted here
|
||
if a > 100 then throw $ IO.userError "Error"
|
||
myPrint b.1 -- liftM inserted here
|
||
pure (a + 1)
|
||
|
||
def h₃ (x : Nat) : StateT Nat IO Nat := do
|
||
let m1 := do -- Type inferred from application below
|
||
discard <| g x -- liftM inserted here
|
||
IO.println 1
|
||
let m2 (y : Nat) := do -- Type inferred from application below
|
||
discard <| h (x+y) -- liftM inserted here
|
||
myPrint y -- liftM inserted here
|
||
let a ← h 1 -- liftM inserted here
|
||
IO.println x
|
||
let b ← g1 a; -- liftM inserted here
|
||
if a > 100 then throw $ IO.userError "Error"
|
||
myPrint b.1 -- liftM inserted here
|
||
m1
|
||
m2 a
|
||
pure 1
|
||
|
||
def tst0 : IO Unit := do
|
||
let a ← f
|
||
let x := a + 1
|
||
IO.println "hello"
|
||
IO.println x
|
||
|
||
def tst1 : IO Unit := do
|
||
let a ← f;
|
||
let x := a + 1;
|
||
IO.println "hello";
|
||
IO.println x;
|
||
|
||
def tst2 : IO Unit := do
|
||
let x := ← g $ (←f) + (←f);
|
||
IO.println "hello";
|
||
IO.println x
|
||
|
||
def tst3 : IO Unit := do
|
||
if (← g 1) > 0 then
|
||
IO.println "gt"
|
||
else
|
||
let x ← f;
|
||
let y ← g x;
|
||
IO.println y
|
||
|
||
def pred (x : Nat) : IO Bool := do
|
||
return (← g x) > 0
|
||
|
||
def tst4 (x : Nat) : IO Unit := do
|
||
if ← pred x then
|
||
IO.println "is true"
|
||
else
|
||
IO.println "is false"
|
||
|
||
def pred2 (x : Nat) : IO Bool := do
|
||
return x > 0
|
||
|
||
def tst5 (x : Nat) : IO (Option Nat) :=
|
||
if x > 10 then pure x else pure none
|
||
|
||
def tst6 (x : Nat) : StateT Nat IO (Option Nat) :=
|
||
if x > 10 then g x else pure none
|
||
|
||
syntax:max (name := doHash) "#" : term
|
||
|
||
partial def expandHash : Syntax → StateT Bool MacroM Syntax
|
||
| Syntax.node i k args =>
|
||
if k == `doHash then do set true; `(←MonadState.get)
|
||
else do
|
||
let args ← args.mapM expandHash;
|
||
pure $ Syntax.node i k args;
|
||
| stx => pure stx
|
||
|
||
@[macro Lean.Parser.Term.do] def expandDo : Macro :=
|
||
fun stx => do
|
||
let (stx, expanded) ← expandHash stx false;
|
||
if expanded then pure stx
|
||
else Macro.throwUnsupported
|
||
|
||
|
||
def tst7 : StateT (Nat × Nat) IO Unit := do
|
||
if #.1 == 0 then
|
||
IO.println "first field is zero"
|
||
else
|
||
IO.println "first field is not zero"
|
||
|
||
/-- info: tst7 : StateT (Nat × Nat) IO Unit -/
|
||
#guard_msgs in
|
||
#check tst7
|
||
|
||
/--
|
||
info: first field is zero
|
||
---
|
||
info: ((), 0, 2)
|
||
-/
|
||
#guard_msgs in
|
||
#eval tst7.run (0, 2)
|
||
|
||
def f1 (x : Nat) : StateT Nat IO Nat := do
|
||
IO.println "hello"
|
||
let mut z := x
|
||
let mut y := x
|
||
modify (· + 10)
|
||
if x > 0 then
|
||
y := 3*y
|
||
z := z + (← get) + (← get)
|
||
if x < (← get) then
|
||
IO.println s!">> {y}"
|
||
return y
|
||
else
|
||
IO.println s!"++ {z}"
|
||
return y+z
|
||
|
||
def f1Test : IO Unit := do
|
||
unless (← f1 30 |>.run' 0) == 140 do
|
||
throw $ IO.userError $ "error"
|
||
unless (← f1 5 |>.run' 0) == 15 do
|
||
throw $ IO.userError $ "error"
|
||
|
||
/--
|
||
info: hello
|
||
++ 50
|
||
hello
|
||
>> 15
|
||
-/
|
||
#guard_msgs in
|
||
#eval f1Test
|