Zulip Chat Archive
Stream: lean4
Topic: Funcs with implicit parameters hard to read
Max Nowak 🐉 (Dec 20 2023 at 14:34):
I have the following minimized problem. For some reason, taker nop
renders as taker fun {A} => nop
in the infoview, which is very distracting and hard to read. In some places I can fix this by writing taker @nop
instead.
It's eta equivalent, but annoying.
inductive Ty : Type | ty
inductive Tm : Ty -> Type | tm : Tm .ty
def Subb : Type _ := {A : Ty} -> (var_idx : Nat) -> Tm A
def nop : Subb := fun {A} idx => .tm
def taker : Subb -> String := sorry
#check taker nop -- taker fun {A} => nop : String
set_option pp.all true
def ohno := taker nop
def ohyes := taker @nop
#print ohno -- taker fun {A : Ty} => @nop A
#print ohyes -- taker @nop
I assume that would be very hard to fix and would require the elaborator or delaborator to be changed.
Is there a better way of handling these? Does someone have a delaborator for this written already? Maybe there is a tactic which will eta-simplify?
Eric Wieser (Dec 20 2023 at 15:04):
The fact that these two print in different ways suggests that what you want is an elaborator change, not a delaborator change.
Max Nowak 🐉 (Dec 20 2023 at 15:23):
Yeah... I take it there is no easy solution, other than just not using implicit arguments like this?
Kyle Miller (Dec 20 2023 at 16:15):
I find this to be surprising behavior. Why is the elaborator unfolding Subb
? The type of nop
is Subb
, so where is it getting the idea that it needs to see that there is an implicit argument hidden behind the definition of Subb
?
Max Nowak 🐉 (Dec 20 2023 at 16:18):
Oh yeah I didn't even notice that, that's even weirder.
Mario Carneiro (Dec 20 2023 at 16:19):
I think implicit lambdas always do this?
Mario Carneiro (Dec 20 2023 at 16:19):
they are eagerly inserted and then canceled using implicit arguments (producing an eta redex) if needed
Kyle Miller (Dec 20 2023 at 16:21):
That would make sense to me if there were any implicit lambdas that the elaborator could immediately see in the types of taker
or nop
, but does it see that nop
is an implicit lambda? Or that Subb
is a type with an implicit forall?
Mario Carneiro (Dec 20 2023 at 16:22):
Max Nowak 🐉 said:
Yeah... I take it there is no easy solution, other than just not using implicit arguments like this?
well, implicit foralls in definitions are generally avoided for exactly this reason. Normally when you want this in a definition like src#Set.Subset you use semi-implicits instead (this is their main motivation)
Kyle Miller (Dec 20 2023 at 16:22):
Oh, the implicit lambda feature does whnf on the expected type, right? Actually, never mind, this doesn't explain the behavior of nop
for me, since it's not a lambda unless you unfold it.
Mario Carneiro (Dec 20 2023 at 16:24):
implicit lambda triggers basically whenever you call elabTerm
, it doesn't require there to be a lambda expected or a forall goal
Mario Carneiro (Dec 20 2023 at 16:25):
it's an optional parameter to the function: docs#Lean.Elab.Term.elabTerm
Max Nowak 🐉 (Dec 20 2023 at 16:28):
I think the semi implicit binders are exactly what I was looking for
Last updated: May 02 2025 at 03:31 UTC