Zulip Chat Archive
Stream: new members
Topic: let pattern matching not work
AlanHacker (Jun 09 2025 at 11:01):
Hi all! I have a question regarding let bindings and pattern matching.
In "Functional Programming in Lean" 4.3, section exercises, there's an example that uses a inductive type like this:
inductive ToTrace (α : Type) where
| trace : α → ToTrace α
When I try to extract the value inside ToTrace using a let binding like this:
def applyTraced (op : ToTrace (Prim Empty)) (x : Int) (y : Int)
: WithLog (Prim Empty × Int × Int) Int :=
let ToTrace.trace p := op
match p with
| Prim.plus =>
save (Prim.plus, x, y) >>= fun () =>
pure (x + y)
| Prim.minus =>
save (Prim.minus, x, y) >>= fun () =>
pure (x - y)
| Prim.times =>
save (Prim.times, x, y) >>= fun () =>
pure (x * y)
Lean reports an "unknown identifier 'p'" error.
Is there a specific reason why user-defined inductive types (even with a single constructor) are not allowed in let pattern matches?
Thanks in advance!
Aaron Liu (Jun 09 2025 at 11:03):
Can you provide a #mwe?
AlanHacker (Jun 09 2025 at 11:09):
inductive Prim (α : Type) : Type where
| plus : Prim α
| minus : Prim α
| times : Prim α
structure WithLog (logged : Type) (α : Type) where
log : List logged
val : α
def save {logged : Type} (data : logged) : WithLog logged Unit :=
{ log := [data], val := () }
instance {logged : Type} : Monad (WithLog logged) where
pure x := { log := [], val := x }
bind r f :=
let { log := l₁, val := x } := r
let { log := l₂, val := y } := f x
{ log := l₁ ++ l₂, val := y }
inductive ToTrace (α : Type) : Type where
| trace : α → ToTrace α
def applyTraced (op : ToTrace (Prim Empty)) (x y : Int)
: WithLog (Prim Empty × Int × Int) Int :=
let ToTrace.trace p := op
match p with -- unknown identifier 'p'
| Prim.plus => save (Prim.plus, x, y) >>= fun _ => pure (x + y)
| Prim.minus => save (Prim.minus, x, y) >>= fun _ => pure (x - y)
| Prim.times => save (Prim.times, x, y) >>= fun _ => pure (x * y)
I was expecting the pattern let ToTrace.trace p := op to work, since ToTrace only has one constructor.
Aaron Liu (Jun 09 2025 at 11:24):
def applyTraced (op : ToTrace (Prim Empty)) (x y : Int)
: WithLog (Prim Empty × Int × Int) Int :=
let .trace p := op
match p with
| Prim.plus => save (Prim.plus, x, y) >>= fun _ => pure (x + y)
| Prim.minus => save (Prim.minus, x, y) >>= fun _ => pure (x - y)
| Prim.times => save (Prim.times, x, y) >>= fun _ => pure (x * y)
AlanHacker (Jun 09 2025 at 11:42):
Thanks! That works — but I’m curious, why does this work?
Aaron Liu (Jun 09 2025 at 11:51):
I don't know, it must be something with the parsing
Kyle Miller (Jun 09 2025 at 19:56):
This is another workaround:
let (ToTrace.trace p) := op
Without the parentheses, it's interpreting the let as defining a new local function named ToTrace.trace.
Last updated: Dec 20 2025 at 21:32 UTC