Zulip Chat Archive

Stream: lean4

Topic: subtypes and `(a : α)`


David Renshaw (Jul 31 2021 at 12:54):

In Lean 3 we have:

def extract_val {α : Type} (p : α  Prop) (a : {x // p x}) := (a : α)
#print extract_val

-- 115:1: def extract_val : Π {α : Type} (p : α → Prop), {x // p x} → α :=
--  λ {α : Type} (p : α → Prop) (a : {x // p x}), ↑a

i.e. (a : α) expands to ↑a, which further elaborates to some coe stuff.

In Lean 4 we instead have:

def extract_val {α : Type} (p : α  Prop) (a : {x // p x}) := (a : α)
#print extract_val

-- def extract_val : {α : Type} → (p : α → Prop) → (Subtype fun (x : α) => p x) → α :=
--  fun {α : Type} (p : α → Prop) (a : Subtype fun (x : α) => p x) => a.val

i.e. (a : α) expands directly to a.val, with no apparent intermediate steps.

My question is: where is the logic governing that expansion in the Lean 4 version? Is it still going through coe somehow, but getting normalized before I can print it? Or is there some other magic somewhere?

Mario Carneiro (Jul 31 2021 at 12:58):

It uses coe like lean 3, but the definition of the coercion is used directly rather than using the generic arrow

Gabriel Ebner (Jul 31 2021 at 13:03):

David Renshaw said:

My question is: where is the logic governing that expansion in the Lean 4 version?

As Mario said, you still declare the coercions by adding instances for the Coe type class. The expansion is done here:
https://github.com/leanprover/lean4/blob/479edbe2359b549c59b7d3de6e61a7f576e0df00/src/Lean/Elab/BuiltinNotation.lean#L243-L249
https://github.com/leanprover/lean4/blob/d0996fb9450dc37230adea9d10ecfdf10330ef67/src/Lean/Meta/Coe.lean#L24-L40

David Renshaw (Jul 31 2021 at 13:46):

It uses coe like lean 3, but the definition of the coercion is used directly rather than using the generic arrow

The uparrow is notation for coe:
https://github.com/leanprover/lean4/blob/32bea737089f5153cef65e480601e2e610973222/src/Init/Coe.lean#L62

So I'm a bit confused about what would be different about using one or the other.

David Renshaw (Jul 31 2021 at 13:47):

https://github.com/leanprover/lean4/blob/d0996fb9450dc37230adea9d10ecfdf10330ef67/src/Lean/Meta/Coe.lean#L24-L40

This appears to validate my hypothesis that the main difference between Lean 3 and Lean 4 here is that Lean 4 is doing more normalization sooner.

Gabriel Ebner (Jul 31 2021 at 14:19):

David Renshaw said:

It uses coe like lean 3, but the definition of the coercion is used directly rather than using the generic arrow

The uparrow is notation for coe:
https://github.com/leanprover/lean4/blob/32bea737089f5153cef65e480601e2e610973222/src/Init/Coe.lean#L62

I'd avoid the uparrow completely since it produces a different expression than the type annotation. We should probably change it to a custom elaborator so that it does the same thing as the regular coercion.

Gabriel Ebner (Jul 31 2021 at 14:22):

Is it still going through coe somehow, but getting normalized before I can print it?

Missed this one, you're almost right except for the time point. The normalization happens during elaboration.

Mario Carneiro (Jul 31 2021 at 14:29):

Should we reverse the transformation in delab / pretty printing? I see arguments both ways

Gabriel Ebner (Jul 31 2021 at 14:37):

I think a pp.coe option would be good for common stuff (like Int.ofNat, etc.). But we can add this very easily in mathlib.

Mario Carneiro (Jul 31 2021 at 14:39):

As in, we have one pp.coe option that turns on all uses of the arrow instead of coe-unfoldings, or we have an attribute that selects particular coercions that are affected by pp.coe and others are always expanded?

Gabriel Ebner (Jul 31 2021 at 14:40):

One pp.coe option that prints the arrow instead of the specific functions.

Gabriel Ebner (Jul 31 2021 at 14:40):

(Or even nothing.)

Mario Carneiro (Jul 31 2021 at 14:41):

I would go for using the arrow by default (not nothing and not the expansion), and the others can be pp options

Mac (Jul 31 2021 at 18:34):

Mario Carneiro said:

Should we reverse the transformation in delab / pretty printing? I see arguments both ways

I'm curious: how would one reverse the coe? Isn't the information that a function application came from a coe lost during elaboration?

Mario Carneiro (Jul 31 2021 at 19:34):

I believe you can attach the delab to whatever expression is used in the coe, unless it is too basic (i.e. an identity function or a lambda or other built in syntax)

Mario Carneiro (Jul 31 2021 at 19:35):

I think we will need to have a best practice around using only coes of the form func x or things only marginally more complicated than that, so that there is a definition to attach the delab to


Last updated: Dec 20 2023 at 11:08 UTC