Zulip Chat Archive
Stream: new members
Topic: rec_on noob question
Mateusz Zugaj (Jul 05 2020 at 16:03):
bool.rec_on tt 1 2
- Shouldn't this be equal to 1? But It doesn't work, I get the error
invalid 'bool.rec_on' application, elaborator has special support for this kind of application (it is handled as an "eliminator"), but the expected type must be known
The expected type
- it means nat
? Where to put it?
Reid Barton (Jul 05 2020 at 16:19):
(bool.rec_on tt 1 2 : nat)
Mateusz Zugaj (Jul 05 2020 at 16:51):
I would've never put it there lol
Mateusz Zugaj (Jul 05 2020 at 16:53):
Could you explain how this helps?
Mateusz Zugaj (Jul 05 2020 at 17:00):
I find it bizzare that the compiler (interpreter?) doesn't know how to compute it, but if I tell what's is the type of the output then it suddenly knows
Reid Barton (Jul 05 2020 at 17:01):
The error message tells the reason. If you just wrote something like #eval bool.rec_on tt 1 2
then there is no expected type.
Reid Barton (Jul 05 2020 at 17:02):
Consider the type of bool.rec_on
: Π {C : bool → Sort l} (n : bool), C ff → C tt → C n
. The type checker has to infer C
from limited evidence.
Reid Barton (Jul 05 2020 at 17:03):
Note that C
is a function that takes a bool
and produces a type and we do not give C
explicitly. Thus, Lean has to solve a higher-order unification problem.
Mario Carneiro (Jul 05 2020 at 17:04):
The reason the compiler can't compute it is because it's not a complete term. It's actually @bool.rec_on <guess me> tt 1 2
and lean was unable to do the guessing part. The interpreter will not even consider evaluating terms with unresolved metavariables
Reid Barton (Jul 05 2020 at 17:04):
In general there is no unique answer to such unification problems. Lean has a heuristic to solve them but it depends on knowing the expected type.
Mario Carneiro (Jul 05 2020 at 17:05):
Notice that (bool.rec_on tt 1 2 : int)
also works and gives a different answer
Reid Barton (Jul 05 2020 at 17:06):
If you had a nondependent recursor like bool.foo : \Pi (T : Type), bool -> T -> T -> T
then Lean would be able to fall back to inferring T
from the arguments instead.
Mario Carneiro (Jul 05 2020 at 17:07):
By the way cond tt 2 1
works fine, because it is nondependent like Reid says
Mateusz Zugaj (Jul 05 2020 at 17:14):
Okay, I see that we do not give C
explicitly. If I want to give it explicitly, what would I need to write?
Mateusz Zugaj (Jul 05 2020 at 17:15):
λ b : bool, nat
?
Mateusz Zugaj (Jul 05 2020 at 17:16):
It works, but I'm not sure whether I understand the role of C
.
Kevin Buzzard (Jul 05 2020 at 17:27):
C tells you the type of the object you're making, and the output of the recursor is the term of that type
Mateusz Zugaj (Jul 05 2020 at 18:05):
But cond
seems to handle just fine without it
Bryan Gin-ge Chen (Jul 05 2020 at 18:08):
Here's the type of cond
: cond : Π {a : Type u_1}, bool → a → a → a
. This is a non-dependent function. See Reid's most recent message in this thread.
Mario Carneiro (Jul 05 2020 at 18:30):
Note that bool.rec_on
can be used where the types of the two sides are not the same (i.e. 1 : nat
and 2 : int
)
Mario Carneiro (Jul 05 2020 at 18:30):
in which case the result will have a funny dependent type
Mateusz Zugaj (Jul 05 2020 at 20:10):
@Mario Carneiro Wow, that's a great answer, thank you!
Mateusz Zugaj (Jul 05 2020 at 20:10):
But know I'm stuck in a circle, because in order to define this dependent type, I would need to use bool.rec_on
itself
Mateusz Zugaj (Jul 05 2020 at 20:11):
Like (λ b : bool, bool.rec_on b nat int)
Bryan Gin-ge Chen (Jul 05 2020 at 20:14):
When you declare bool
as an inductive type you get bool.rec_on
for free. There's a nice explanation by @Kevin Buzzard here: https://xenaproject.wordpress.com/2018/03/24/no-confusion-over-no_confusion/
Mateusz Zugaj (Jul 05 2020 at 20:17):
Yeah, I know this at least.
Mateusz Zugaj (Jul 05 2020 at 20:18):
But I think this is not the easiest way to use it:
@bool.rec_on (λ b : bool, @bool.rec_on (λ b1 : bool, Type) b nat bool ) tt 2 ff
Mario Carneiro (Jul 05 2020 at 20:19):
you can use cond
for that, because nat
and int
have the same type, namely Type
:)
Mateusz Zugaj (Jul 05 2020 at 20:20):
oh right
Mateusz Zugaj (Jul 05 2020 at 20:20):
But in the general case, like for the type weekday
from the tutorial (inductive type with 7 elements) it wouldn't work
Mario Carneiro (Jul 05 2020 at 20:21):
#eval (bool.rec_on tt (2:nat) ff : cond tt bool nat)
#eval (bool.rec_on ff (2:nat) ff : cond ff bool nat)
Mario Carneiro (Jul 05 2020 at 20:22):
the display isn't great because lean doesn't know how to infer a to_string function for this type
Mario Carneiro (Jul 05 2020 at 20:23):
I will note that it is pretty weird to be writing types or programs like this
Mateusz Zugaj (Jul 05 2020 at 20:24):
At least I now understand fully what's going on
Mateusz Zugaj (Jul 05 2020 at 20:24):
Thank you really much!
Mateusz Zugaj (Jul 05 2020 at 20:27):
#reduce
works better than #eval
there
Mario Carneiro (Jul 05 2020 at 20:27):
inductive weekday : Type | mon | tue | wed | thu | fri | sat | sun
def tgif_type : weekday → Type
| weekday.fri := string
| _ := unit
def tgif (w) : tgif_type w :=
begin
cases w,
case weekday.fri { exact "thank god it's friday" },
all_goals { exact () }
end
instance {w} : has_repr (tgif_type w) :=
begin
cases w,
case weekday.fri { exact string.has_repr },
all_goals { exact ⟨λ _, "()"⟩ }
end
#eval tgif weekday.fri -- "thank god it's friday"
#eval tgif weekday.sun -- ()
Mateusz Zugaj (Jul 05 2020 at 20:35):
When I did #reduce
at the last line my server crashed lol
Floris van Doorn (Jul 05 2020 at 23:51):
From the perspective of the kernel (that #reduce
uses) strings are a list characters, which are natural numbers in a certain range. From the perspective of the kernel, natural numbers are written unary, as S (S ( ... 0 ... ))
, so it chokes on even medium-sized natural numbers.
In short: don't use #reduce
on natural numbers >1000
or char
or string
(or things that are build on a tower of definitions, like any real number)
Last updated: Dec 20 2023 at 11:08 UTC