Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dot notation and CoeFun #1910

Closed
Vtec234 opened this issue Dec 2, 2022 · 1 comment · Fixed by #5692
Closed

Dot notation and CoeFun #1910

Vtec234 opened this issue Dec 2, 2022 · 1 comment · Fixed by #5692
Labels
RFC Request for comments

Comments

@Vtec234
Copy link
Member

Vtec234 commented Dec 2, 2022

Description

This is a question that came up in mathport, resulting from an incompatibility between how dot notation is elaborated in Leans 3 and 4.

In Lean 3, we can (mis?)use dot notation in cases where the applied constant is in the right namespace but does not have an argument of the right type. In the example below

structure equiv (α : Sort*) (β : Sort*) :=
(to_fun    : α → β)
(inv_fun   : β → α)

infix ` ≃ `:25 := equiv

instance {α : Sort*} {β : Sort*} : has_coe_to_fun (α ≃ β) (λ _, α → β) :=
  ⟨equiv.to_fun⟩

def foo := nat
def bar := nat
def foo.to_bar : foo ≃ bar := ⟨id, id⟩

example (f : foo) : f.to_bar = f.to_bar := rfl

the term f.to_bar is first transformed to foo.to_bar f, at which point the standard function application elaborator kicks in and finds a has_coe_to_fun instance. The current community edition implementation is described in the last paragraph here. In practice, this is used for applying bundled morphisms (with equivalences being a special case) as if they were functions, for example enat.to_nat.

In Lean 4, this does not work.

structure Equiv (α β : Sort _) where
  toFun : α → β
  invFun : β → α

infixl:25 "" => Equiv

instance: CoeFun (α ≃ β) fun _ => α → β where
  coe := Equiv.toFun

def Foo := Nat
def Bar := Nat
def Foo.to_Bar : Foo ≃ Bar := ⟨id, id⟩

/- invalid field notation, function 'Foo.to_Bar' does not have argument with type (Foo ...)
that can be used, it must be explicit or implicit with an unique name -/
example (f : Foo) : f.to_Bar = f.to_Bar := sorry

From the Zulip discussion it seems that this is useful to have but it is not immediately clear whether Lean 4 should definitely have this feature, so this is a request for feedback.

@leodemoura leodemoura added the RFC Request for comments label Dec 2, 2022
@gebner gebner added the dev meeting It will be discussed at the (next) dev meeting label Dec 14, 2022
@jcommelin
Copy link
Contributor

Another example from mathlib: Multiset.card {α} : Multiset α →+ ℕ

@leodemoura leodemoura removed the dev meeting It will be discussed at the (next) dev meeting label Nov 7, 2023
kmill added a commit that referenced this issue Oct 13, 2024
Projects like mathlib use projection fields with extra structure, for example one could imagine defining `Multiset.card : Multiset α →+ Nat`, which bundles the fact that `Multiset.card (m1 + m2) = Multiset.card m1 + Multiset.card m2`. A problem though is that so far this has prevented dot notation from working: you can't write `(m1 + m2).card = m1.card + m2.card`.

With this PR, now we can. The way it works is that "LValue resolution" will apply CoeFun instances when trying to resolve which argument should receive the object of dot notation.

This also adds in a small optimization that the parameter list computation in LValue resolution uses `forallTelescope` instead of `forallTelescopeReducing`, lazily reducing when a relevant parameter hasn't been found yet.

Closes #1910
github-merge-queue bot pushed a commit that referenced this issue Oct 14, 2024
Projects like mathlib like to define projection functions with extra
structure, for example one could imagine defining `Multiset.card :
Multiset α →+ Nat`, which bundles the fact that `Multiset.card (m1 + m2)
= Multiset.card m1 + Multiset.card m2` for all `m1 m2 : Multiset α`. A
problem though is that so far this has prevented dot notation from
working: you can't write `(m1 + m2).card = m1.card + m2.card`.

With this PR, now you can. The way it works is that "LValue resolution"
will apply CoeFun instances when trying to resolve which argument should
receive the object of dot notation.

A contrived-yet-representative example:
```lean
structure Equiv (α β : Sort _) where
  toFun : α → β
  invFun : β → α

infixl:25 " ≃ " => Equiv

instance: CoeFun (α ≃ β) fun _ => α → β where
  coe := Equiv.toFun

structure Foo where
  n : Nat

def Foo.n' : Foo ≃ Nat := ⟨Foo.n, Foo.mk⟩

variable (f : Foo)
#check f.n'
-- Foo.n'.toFun f : Nat
```

Design note 1: While LValue resolution attempts to make use of named
arguments when positional arguments cannot be used, when we apply CoeFun
instances we disallow making use of named arguments. The rationale is
that argument names for CoeFun instances tend to be random, which could
lead dot notation randomly succeeding or failing. It is better to be
uniform, and so it uniformly fails in this case.

Design note 2: There is a limitation in that this will *not* make use of
the values of any of the provided arguments when synthesizing the CoeFun
instances (see the tests for an example), since argument elaboration
takes place after LValue resolution. However, we make sure that
synthesis will fail rather than choose the wrong CoeFun instance.

Performance note: Such instances will be synthesized twice, once during
LValue resolution, and again when applying arguments.

This also adds in a small optimization to the parameter list computation
in LValue resolution so that it lazily reduces when a relevant parameter
hasn't been found yet, rather than using `forallTelescopeReducing`. It
also switches to using `forallMetaTelescope` to make sure the CoeFun
synthesis will fail if multiple instances could apply.

Getting this to pretty print will be deferred to future work.

Closes #1910
mathlib-bors bot pushed a commit to leanprover-community/mathlib4 that referenced this issue Nov 23, 2024
…ing lean4 issue #1910 (#19380)

this PR removes 3 porting notes regarding lean4 issue leanprover/lean4#1910, and makes adaptations to mathlib to make use of the newly working notation. Concretely, that means that `OrderHom.lfp f` now is written `f.lfp`, and similar for `OrderHom.dual` and `OrderHom.gfp`.

there might still be some `dual x` application left inside code with `open OrderHom`, but those are hard to filter for with grep, as there are many declarations named `dual` in different namespaces.
mathlib-bors bot pushed a commit to leanprover-community/mathlib4 that referenced this issue Nov 23, 2024
…issue #1910 to refer to lean4 issue #1629 instead (#19381)

These notes refer to the fact that `LinearMap.ker` and friends cannot be used as `f.ker`. However, this fails not because
the function `LinearMap.ker` needs to be coerced to a proper function (which the issue leanprover/lean4#1910 is about), but because the argument `f` has a type (`LinearMap`) that doesn't occur directly as type of an argument to `LinearMap.ker`. The issue leanprover/lean4#1629 *does* suggest a fix for this.
mathlib-bors bot pushed a commit to leanprover-community/mathlib4 that referenced this issue Nov 23, 2024
…o refer to lean4 issue #6178 instead  (#19385)

These adaptation notes refer to the `pp_nodot` attribute not doing anything on certain declarations, due to their inability to be used with dot notation. However, now that leanprover/lean4#1910 has been fixed, the limiting factor has become the fact that the pretty printer doesn't work for these kinds of dot notation, which leanprover/lean4#6178 is an issue for.

As such, the links to the blocking lean issue have been changed in this PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFC Request for comments
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants