Zulip Chat Archive
Stream: general
Topic: Question on `let`
Peter Pfaffelhuber (Mar 28 2025 at 13:04):
I know that bracketing can be tricky. For let
, my working hypotehsis was that let h : α := ...
and let (h : α) := ...
are the same, but apparently this is not the case. Here is a MWE:
Here, rfl
gives an error, saying that q
is not definitionally equal to 1
...
example : True := by
let (q : ℕ) := 1
have hq : q = 1 := by
rfl
sorry
...while everything works fine without the brackets...
example : True := by
let q : ℕ := 1
have hq : q = 1 := by
rfl
sorry
Can someone explain to my why that is?
Mario Carneiro (Mar 28 2025 at 13:06):
no, the syntax of let/have is like have (name)? (binders)? (: type)? := value
, and the name
cannot be in parentheses, so when you put parentheses it gets interpreted as a binder. have (x : A) := x
is a definition of the identity function named this
Mario Carneiro (Mar 28 2025 at 13:07):
for let
it's slightly more complicated because let
doesn't allow the name to be optional (not exactly sure why, it may be on some stage of being changed to be more like have
). So it is probably just a syntax error to do let (q : ℕ) := 1
?
Mario Carneiro (Mar 28 2025 at 13:10):
ah, looks like the syntax unification has already happened, let
acts the same as have
. So let (q : ℕ) := 1
is equivalent to let this (q : ℕ) := 1
or let this := fun (q : ℕ) => 1
, it declares a constant function
Edward van de Meent (Mar 28 2025 at 13:12):
that doesn't seem to be the case, looking at the tactic state after the let?
Peter Pfaffelhuber (Mar 28 2025 at 13:14):
Ok, I understand this, thanks. However, when I use let (q : ℕ) := 1
, the infoveiw in the next line tells me that q : ℕ
, so it is not a function. (When I use let q : ℕ := 1
, the proof state tells me q : ℕ := 1
.)
Edward van de Meent (Mar 28 2025 at 13:14):
in particular, the effect seems more like refine (fun q => ?a) (1:Nat)
Peter Pfaffelhuber (Mar 28 2025 at 13:16):
Edward van de Meent schrieb:
in particular, the effect seems more like
refine (fun q => ?a) (1:Nat)
That`s right, the proof state looks exactly the same...
Mario Carneiro (Mar 28 2025 at 13:28):
that seems like a bug then?
Mario Carneiro (Mar 28 2025 at 13:28):
for have
it produces a function, and I think we definitely don't want divergence between them
Mario Carneiro (Mar 28 2025 at 13:31):
I was wrong, the let this
PR has not merged yet. This isn't a parse error, it's interpreted as a pattern matching let
Mario Carneiro (Mar 28 2025 at 13:32):
but the pattern expression is just a type ascription
Mario Carneiro (Mar 28 2025 at 13:33):
so it ends up equivalent to have ((q : Nat)) := 1
Mario Carneiro (Mar 28 2025 at 13:34):
I lied earlier, the syntax of have is not just have (name)? (binders)* (: type)? := value
, there is a second form which is have (pattern) (: type)? := value
, with no binders and no name allowed
Mario Carneiro (Mar 28 2025 at 13:34):
and (pattern)
here is just term
, it accepts any term and rejects anything that doesn't resolve to some constructor expression (more or less)
Mario Carneiro (Mar 28 2025 at 13:35):
but type ascriptions are allowed in patterns
Mario Carneiro (Mar 28 2025 at 13:35):
and let (pattern) := value
is identical to have (pattern) := value
, i.e. it doesn't actually produce a let binding
Edward van de Meent (Mar 28 2025 at 13:49):
ah right, like how in do-notation you can write let .some a := [0,2].get? 2
Edward van de Meent (Mar 28 2025 at 13:49):
that makes more sense
Mario Carneiro (Mar 28 2025 at 13:49):
yes, or let (x, y) := (1, 2)
Mario Carneiro (Mar 28 2025 at 13:49):
which does not produce let bindings even though people might hope for it
Last updated: May 02 2025 at 03:31 UTC