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
4.7 KiB
Text
158 lines
4.7 KiB
Text
import Lean.Expr
|
|
|
|
open Lean
|
|
|
|
def tst1 : IO Unit :=
|
|
do let f := mkConst `f [];
|
|
let a := mkConst `a [];
|
|
let b := mkConst `b [];
|
|
let t := mkAppN f #[a, b, b];
|
|
let as₁ := t.getAppArgs;
|
|
let as₂ := t.getAppRevArgs;
|
|
IO.println as₁;
|
|
IO.println as₂;
|
|
unless as₁.reverse == as₂ do throw $ IO.userError "failed";
|
|
pure ()
|
|
|
|
/--
|
|
info: #[a, b, b]
|
|
#[b, b, a]
|
|
-/
|
|
#guard_msgs in
|
|
#eval tst1
|
|
|
|
def tst2 : IO Unit :=
|
|
do let l1 := mkLevelMax (mkLevelParam `a) (mkLevelParam `b);
|
|
let l2 := mkLevelMax (mkLevelParam `b) (mkLevelParam `a);
|
|
IO.println l1;
|
|
IO.println l2;
|
|
unless Level.isEquiv l1 l2 do throw $ IO.userError "not equiv";
|
|
pure ()
|
|
|
|
/--
|
|
info: max a b
|
|
max b a
|
|
-/
|
|
#guard_msgs in
|
|
#eval tst2
|
|
|
|
def tst3 : IO Unit :=
|
|
do let f := mkConst `f [];
|
|
let a := mkConst `a [];
|
|
let b := mkConst `b [];
|
|
let c := mkConst `c [];
|
|
let t := mkAppN f #[a, b, c];
|
|
IO.println $ t.getArg! 0;
|
|
IO.println $ t.getArg! 1;
|
|
IO.println $ t.getArg! 2;
|
|
pure ()
|
|
|
|
/--
|
|
info: a
|
|
b
|
|
c
|
|
-/
|
|
#guard_msgs in
|
|
#eval tst3
|
|
|
|
|
|
def tst4 : IO Unit :=
|
|
do let f := mkConst `f [];
|
|
let a := mkConst `a [];
|
|
let b := mkConst `b [];
|
|
let x0 := mkBVar 0;
|
|
let x1 := mkBVar 1;
|
|
let t1 := mkAppN f #[a, b];
|
|
let t2 := mkAppN f #[a, x0];
|
|
let t3 := mkLambda `x BinderInfo.default (mkSort levelZero) (mkAppN f #[a, x0]);
|
|
let t4 := mkLambda `x BinderInfo.default (mkSort levelZero) (mkAppN f #[a, x1]);
|
|
unless (!t1.hasLooseBVar 0) do throw $ IO.userError "failed-1";
|
|
unless (t2.hasLooseBVar 0) do throw $ IO.userError "failed-2";
|
|
unless (!t3.hasLooseBVar 0) do throw $ IO.userError "failed-3";
|
|
unless (t4.hasLooseBVar 0) do throw $ IO.userError "failed-4";
|
|
unless (!t4.hasLooseBVar 1) do throw $ IO.userError "failed-5";
|
|
unless (!t2.hasLooseBVar 1) do throw $ IO.userError "failed-6";
|
|
pure ()
|
|
|
|
#guard_msgs in
|
|
#eval tst4
|
|
|
|
def tst5 : IO Unit :=
|
|
do let f := mkConst `f [];
|
|
let a := mkConst `a [];
|
|
let nat := mkConst `Nat [];
|
|
let x0 := mkBVar 0;
|
|
let x1 := mkBVar 1;
|
|
let x2 := mkBVar 2;
|
|
let t := mkLambda `x BinderInfo.default nat (mkApp f x0);
|
|
IO.println t.etaExpanded?;
|
|
unless (t.etaExpanded? == some f) do throw $ IO.userError "failed-1";
|
|
let t := mkLambda `x BinderInfo.default nat (mkApp f x1);
|
|
unless (t.etaExpanded? == none) do throw $ IO.userError "failed-2";
|
|
let t := mkLambda `x BinderInfo.default nat (mkAppN f #[a, x0]);
|
|
unless (t.etaExpanded? == some (mkApp f a)) do throw $ IO.userError "failed-3";
|
|
let t := mkLambda `x BinderInfo.default nat (mkAppN f #[x0, x0]);
|
|
unless (t.etaExpanded? == none) do throw $ IO.userError "failed-4";
|
|
let t := mkLambda `x BinderInfo.default nat (mkLambda `y BinderInfo.default nat (mkApp f x0));
|
|
unless (t.etaExpanded? == none) do throw $ IO.userError "failed-5";
|
|
let t := mkLambda `x BinderInfo.default nat (mkLambda `y BinderInfo.default nat (mkAppN f #[x1, x0]));
|
|
IO.println t;
|
|
unless (t.etaExpanded? == some f) do throw $ IO.userError "failed-6";
|
|
let t := mkLambda `x BinderInfo.default nat (mkLambda `y BinderInfo.default nat (mkLambda `z BinderInfo.default nat (mkAppN f #[x2, x1, x0])));
|
|
IO.println t;
|
|
unless (t.etaExpanded? == some f) do throw $ IO.userError "failed-7";
|
|
let t := mkLambda `x BinderInfo.default nat (mkLambda `y BinderInfo.default nat (mkLambda `z BinderInfo.default nat (mkAppN f #[a, x2, x1, x0])));
|
|
IO.println t;
|
|
unless (t.etaExpanded? == some (mkApp f a)) do throw $ IO.userError "failed-8";
|
|
IO.println t.etaExpanded?;
|
|
let t := mkApp f a;
|
|
unless (t.etaExpanded? == some (mkApp f a)) do throw $ IO.userError "failed-9";
|
|
pure ()
|
|
|
|
/--
|
|
info: (some f)
|
|
fun (x : Nat) (y : Nat) => f x y
|
|
fun (x : Nat) (y : Nat) (z : Nat) => f x y z
|
|
fun (x : Nat) (y : Nat) (z : Nat) => f a x y z
|
|
(some (f a))
|
|
-/
|
|
#guard_msgs in
|
|
#eval tst5
|
|
|
|
def tst6 : IO Unit := do
|
|
let x1 := mkBVar 0;
|
|
let x2 := mkBVar 1;
|
|
let t1 := mkApp2 (mkConst `f) x1 x2;
|
|
let t2 := mkForall `x BinderInfo.default (mkConst `Nat) t1;
|
|
IO.println (t1.liftLooseBVars 0 1);
|
|
IO.println (t2.liftLooseBVars 0 1);
|
|
let t3 := (t2.liftLooseBVars 0 1).lowerLooseBVars 1 1;
|
|
IO.println $ t3;
|
|
unless (t2 == t3) do throw $ IO.userError "failed-1";
|
|
pure ()
|
|
|
|
/--
|
|
info: f #1 #2
|
|
forall (x : Nat), f x #1
|
|
forall (x : Nat), f x #0
|
|
-/
|
|
#guard_msgs in
|
|
#eval tst6
|
|
|
|
instance : Coe Name FVarId where
|
|
coe n := { name := n }
|
|
|
|
def tst7 : IO Unit := do
|
|
let x := mkFVar `x;
|
|
let y := mkFVar `y;
|
|
let f := mkConst `f;
|
|
let t := mkAppN f #[x, y, mkNatLit 2];
|
|
let t := t.abstract #[x, y];
|
|
let t := t.instantiateRev #[mkNatLit 0, mkNatLit 1];
|
|
IO.println t
|
|
|
|
/--
|
|
info: f (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)) (OfNat.ofNat.{0} Nat 1 (instOfNatNat 1)) (OfNat.ofNat.{0} Nat 2 (instOfNatNat 2))
|
|
-/
|
|
#guard_msgs in
|
|
#eval tst7
|