Zulip Chat Archive
Stream: lean4
Topic: anonymous structure
Tomas Skrivan (Nov 04 2025 at 20:57):
For quite some time I wanted to have anonymous structures.
My main use case is when a function returns multiple values. Often I end up defining one time use structure likeFooResult for function foo. However more often I just end up returning a type that looks like _ × _ × _ × _ × _ which I often regret when I read the code after some time.
So I finally took the time and defined anonymous structures. You can write code like
def foo (a : Float) : struct {x : Float, y : Float} :=
{ x := a.cos, y := a.sin }
instance : Add (struct { x : Float, y : Float }) := ⟨fun u v => ⟨u.x+v.x, u.y+v.y⟩⟩
/-- info: { x := 1.916065, y := 0.489252 } -/
#guard_msgs in
#eval
let a := foo 0.1
let b := foo 0.4
a + b
No question here, I just want to share this as I'm sure someone else will find it useful too.
Here is the implementation
code
Kenny Lau (Nov 04 2025 at 20:59):
very nice! just one tiny detail, I would write struct% to make it clear that this is a meta function
Tomas Skrivan (Nov 04 2025 at 21:00):
Ohh one question regardless. Can someone help me to fix the unexpander? It uses syntax quotation inside of quotation and all the identifiers get murdered with ✝
/-- info: struct {x✝:Float✝, y✝:Float✝} : Type -/
#check struct { x : Float, y : Float }
Kenny Lau (Nov 04 2025 at 21:03):
instead of `(struct { $[$names:ident : $types:term],* }) I would do the parsing separately, maybe this would fix that issue
Tomas Skrivan (Nov 04 2025 at 21:07):
Kenny Lau said:
very nice! just one tiny detail, I would write
struct%to make it clear that this is a meta function
Yeah that would work too but I feel that the % notation is used for elaborators that do substantially more complicated things. I feel that anonymous struct is quite a simple concept.
Tomas Skrivan (Nov 05 2025 at 06:36):
Kenny Lau said:
instead of
`(struct { $[$names:ident : $types:term],* })I would do the parsing separately, maybe this would fix that issue
What do you mean by passing separately?
I might be wrong but I thought the issue is in
let cmd ← `(command|
@[app_unexpander $structId]
def unexpandAnonStruct : Lean.PrettyPrinter.Unexpander
| _ => `($stx)
)
which contains nested quotation `
František Silváši 🦉 (Nov 05 2025 at 10:21):
I wonder if this isn't a legitimate use of suspending hygiene:
@[app_unexpander $structId]
def unexpandAnonStruct : Lean.PrettyPrinter.Unexpander
| _ => set_option hygiene false in `($stx)
)
Considering the macro scopes have already been 'handled' by this point (i.e. stx is the thing you want verbatim here)?
Tomas Skrivan (Nov 05 2025 at 10:57):
Thanks a lot! works like a charm!
Yes it feels like a legitimate use case but I don't really understand syntax and macro scopes so hard to say.
Last updated: Dec 20 2025 at 21:32 UTC