Zulip Chat Archive

Stream: general

Topic: unification hints


Johan Commelin (Feb 14 2019 at 08:36):

Can we use unification hints to make sure that we can just write if we want to view the integers as an object of the category CommRing?

Simon Hudon (Feb 14 2019 at 17:18):

I don't think so. Unification hints seem more useful for unbundling a bundled structure than bundling an unbundled one

Johan Commelin (Feb 14 2019 at 17:51):

Too bad... I really liked the notation (-;

Joseph Corneli (Feb 15 2019 at 11:15):

Is there a canonical example of unification hints being used in Lean that someone can point to?

Mario Carneiro (Feb 15 2019 at 11:16):

Cyril and Assia had a demonstration at Lean Together, I wonder if that file is available somewhere

Mario Carneiro (Feb 15 2019 at 11:17):

It's never been used in lean core or mathlib outside one example in init.core

Joseph Corneli (Feb 15 2019 at 13:13):

I emailed them to ask about the file!

Cyril Cohen (Feb 15 2019 at 13:14):

Hi! Both the Coq demo and the Lean equivalent are available on https://lean-forward.github.io/lean-together/2019/

Cyril Cohen (Feb 15 2019 at 13:16):

Assia Mahboubi: unification hints (in Coq) https://lean-forward.github.io/lean-together/2019/slides/coq_cs_demo.v
Cyril Cohen: unification hints (in Lean) https://lean-forward.github.io/lean-together/2019/slides/demo_structures.lean

Cyril Cohen (Feb 15 2019 at 13:20):

@Johan Commelin

Can we use unification hints to make sure that we can just write if we want to view the integers as an object of the category CommRing?

We, in mathcomp, usually explicitly wrap them e.g. [CommRing of ℤ] to denote the canonical structure associated to a carrier. In Coq there is no way to automate this further to my knowledge. But maybe in Lean you could use some special kind of coercion. Indeed, since coercions are fused with the typeclass system, you could make a coercion from Type that finds the structure and packages it with the type to give you the structure as a result.

Joseph Corneli (Feb 15 2019 at 13:23):

thanks!

Johan Commelin (Feb 15 2019 at 13:25):

@Cyril Cohen I don't follow... you want a coercion from Type to CommRing? But then it has to turn every type into a commutative ring...

Cyril Cohen (Feb 15 2019 at 13:32):

@Johan Commelin only when the inference succeeds in finding a CommRing typeclass on the argument. I'm not sure it works, I'm just guessing it might, given how coercions are implemented in lean.

Cyril Cohen (Feb 15 2019 at 13:35):

@Johan Commelin on second thought, I do not think it is possible ... sorry for the false hopes...

Johan Commelin (Feb 15 2019 at 13:36):

No problem...

Chris Hughes (Feb 15 2019 at 14:18):

How does the coe from Prop to bool work? That's a partial coercion.

Kenny Lau (Feb 15 2019 at 14:27):

@Chris Hughes which files did you import?

Chris Hughes (Feb 15 2019 at 14:30):

I'm afk, but I think it's in core. It only works on decidable props.

Kenny Lau (Feb 15 2019 at 14:30):

to_bool : Π (p : Prop) [h : decidable p], bool

Chris Hughes (Feb 15 2019 at 14:31):

But I don't have to write to_bool

Kenny Lau (Feb 15 2019 at 14:31):

interesting

Andrew Ashworth (Feb 15 2019 at 14:47):

bool to Prop is a special case handled in the C++ code, iirc

Andrew Ashworth (Feb 15 2019 at 14:48):

this will change in some way in lean 4, but I don't remember where I read that

Yaël Dillies (Oct 25 2024 at 18:19):

I have been trying to write a unification hint to get ((s : Finset α) : Set _) to work. Can anyone see what I did wrong?

import Mathlib.Data.Finset.Basic

open Lean Meta

-- @[unify] def finsetToSet {α β : Type*} (s : Finset α) (t : Set β) : UnificationHint where
--   pattern := ⟨`(s), t⟩
--   constraints := [⟨α, β⟩]

unif_hint forget_obj_eq_coe {α β : Type*} (s : Finset α) (t : Set β) where
  [α  β]  s  t
-- unexpected token '≟'; expected ':' or ']'

example {α : Type*} (s : Finset α) : Set.univ  s := sorry
/-
application type mismatch
  Set.univ ⊆ s
argument
  s
has type
  Finset α : Type u_1
but is expected to have type
  Set ?m.342 : Type u_1
-/

François G. Dorais (Oct 25 2024 at 21:49):

I think α and β need t be at the same universe level. But I don't understand what you're trying to do here.

François G. Dorais (Oct 25 2024 at 21:59):

Maybe you mean something like this:

unif_hint guess {α : Type*} (s : Finset α) (t : Set α) (x : α) where
  (s : Set α) =?= t  (x  s) =?= (x  t)

Yaël Dillies (Oct 25 2024 at 23:12):

I am trying to get the example in my MWE working without error

Yaël Dillies (Oct 25 2024 at 23:13):

I don't really understand what membership has to do with it

Yaël Dillies (Oct 25 2024 at 23:15):

It is a huge impediment to the finset library that we can't use s : Set alpha in a function expecting a Set ?beta unless Lean knows that ?beta := alpha. I am trying to make Lean automatically set ?beta := alpha in such a situation.

Kyle Miller (Oct 25 2024 at 23:20):

I'm not too familiar with unification hints, but it seems like the won't work here. The issue is that you're needing a coercion to apply, and it's the coercion that's failing to be synthesized because typeclass synthesis refuses to assign the metavariable in Set _. This assignment can't happen even with hints.

Kevin Buzzard (Oct 25 2024 at 23:23):

But Yael is right, I've run into this and I hardly ever use finsets, so presumably many people have. Is there anything we can do about it?

Kyle Miller (Oct 25 2024 at 23:23):

Coercion has special support for some similar situations, like if Finset and Set were both monads and there were a MonadLift Finset Set instance then it could do something.

It would be nice if there were a system supporting "functorial" coercions, like a coercion from the Finset to Set (not a coercion from Finset X to Set X — a coercion of the type functions themselves)

Kyle Miller (Oct 25 2024 at 23:27):

Somewhat related, we have support for this situation in mathlib in the form of the fbinop% elaborator for docs#SProd.sprod, to be able to elaborate products of sets/finsets/filters.

François G. Dorais (Oct 26 2024 at 01:05):

Yaël Dillies said:

I am trying to get the example in my MWE working without error

For a unification hint to be valid the conclusion has to unify given the unification hypotheses. Your (slightly edited) proposal

unif_hint forget_obj_eq_coe {α β : Type u} (s : Finset α) (t : Set β) where
  α  β  s  t

doesn't work since it says that any such s and t must unify so long as α and β unify. That doesn't make sense (except perhaps when α and β are both empty). I don't understand what you're aiming for.

François G. Dorais (Oct 26 2024 at 01:07):

(Also, the proposed example doesn't appear to be true.)

François G. Dorais (Oct 26 2024 at 01:11):

Yaël Dillies said:

It is a huge impediment to the finset library that we can't use s : Set alpha in a function expecting a Set ?beta unless Lean knows that ?beta := alpha. I am trying to make Lean automatically set ?beta := alpha in such a situation.

So you want this?

unif_hint another_guess (α β : Type u) where
  α  β  Set α  Set β

I don't think that's useful but it works!

Kyle Miller (Oct 26 2024 at 01:15):

Yael misspoke, that doesn't need a unification hint since it already follows from the usual defeq rules. It's for ((s : Finset X) : Set _), getting the coercion to work and propagating the X.

François G. Dorais (Oct 26 2024 at 01:27):

With an example that makes sense, I might be able to figure out the right unification hint (assuming that's what is actually needed).

François G. Dorais (Oct 26 2024 at 01:55):

Did anyone try a HasHSubset class? (Not clear where the extra H should go.)

Yaël Dillies (Oct 26 2024 at 07:16):

Actually that might be a job for a default instance?

Yaël Dillies (Oct 26 2024 at 07:16):

I don't just want this to work for subset notation but any function that expects a set

Bhavik Mehta (Oct 28 2024 at 02:02):

import Mathlib.Data.Finset.Basic

theorem annoying {s : Finset } (hs : s = ) : Set.Subsingleton s := sorry

Here's a massively simplified example of what gets frustrating in practice. Lean gives the error

application type mismatch
  Set.Subsingleton s
argument
  s
has type
  Finset  : Type
but is expected to have type
  Set ?m.102 : Type

but - in my mind - it's clear that Set ℕ is the only sensible choice here. The current workarounds which appear are:
Set.Subsingleton s.toSet or Set.Subsingleton (s : Set ℕ), both of which seem unnecessarily wordy (especially if I have a finset in a type which is less nice to write down). It'd be really nice if I could just write Set.Subsingleton s, and Lean could automatically figure out that a finite set of naturals can be seen as a set of naturals.

Kyle Miller (Oct 28 2024 at 03:41):

I was mentioning earlier that if Set and Finset were both monads and you had a MonadLift instance, then there's already coercion infrastructure for this, but we intentionally disabled the Set monad instance earlier this year because it could be surprising, and it would insert some monad functions that there wasn't any theory about.

MonadLift example

Yaël Dillies (Oct 28 2024 at 07:19):

And what if we made that monad function the default coercion from a finset to a set. How would that be?

François G. Dorais (Oct 28 2024 at 11:59):

In Bhavik's example, unification works fine and unification hints don't work. TC inference fails because the goal is CoeT (Finset Nat) s (Set ?m) but TC inference can't assign the mvar.

Kyle's example works because the TC goal is MonadLiftT Finset Set, which has no unassignable mvars. This is probably the right way to go.

Bhavik Mehta (Oct 28 2024 at 13:00):

Is it at all possible to make TC inference able to assign the mvar in that example?

François G. Dorais (Oct 28 2024 at 13:24):

To make TC inference to assign mvars they need to be semiOutParam or outParam. I'm thinking that with CoeT this is not going to play well with the complex maze of Coe* classes. This is what CoeHead is for but that won't help here, I think. The other mechanism is default instances but I'm skeptical that can be made to work.

Daniel Weber (Oct 28 2024 at 15:12):

Could CoeOut be useful here?

Kyle Miller (Oct 28 2024 at 15:13):

François G. Dorais said:

I'm thinking that with CoeT this is not going to play well with the complex maze of Coe* classes.

Also neither argument to Coe is an output. We'd soon run into examples where we want fun s : Finset _ => (s : Set Nat) to work too.

François G. Dorais said:

Kyle's example works because the TC goal is MonadLiftT Finset Set, which has no unassignable mvars.

Yes and no. That's why the MonadLiftT instance succeeds, but the key fact is that there is special elaborator support for computing coercions using monad lifts.

I would rather that we don't explore using Monad here, but instead come up with a solid proposal for functorial coercions in core. This problem crops up frequently.

Kyle Miller (Oct 28 2024 at 20:21):

There are two axes here:

  1. Given F X and a "functor coercion" from F to G, getting a coercion F X -> G X.
  2. Given F X and a coercion X to Y, getting a coercion F X -> F Y.

The monad coercion system lets you navigate both of these:

-- The monad
example [MonadLiftT m n] (x : m α) : n α := x
-- The type
example [(a : α)  CoeT α a β] [Monad m] (x : m α) : m β := x
-- Both
example [Monad m] [Monad n] [MonadLiftT m n] [(a : α)  CoeT α a β] (x : m α) : n β := x

Questions:

  1. Should the system derive an automatic coercion from Finset Nat to Finset Int?
  2. Should the system derive an automatic coercion from Finset Nat to Set Int?

A "yes" answer to 1 implies a "yes" to 2 by transitivity of coercions.

My own opinion is "no" to these. While it makes sense for monads (monads are values-with-context, the context should be relatively transparent), with containers this is more fraught. (1) For programming, the inserted coercion might insert a completely accidental copying of the entire data structure. (2) For math, I would expect that getting elaboration to succeed would become a lot more slippery due to all these postponed coercion problems. We disabled the Set monad instance in mathlib partly because it wasn't always anticipated. (We also disabled it because it introduced weird monad functions, but that's fixable in principle.)

Yaël Dillies (Oct 28 2024 at 20:24):

My answers:

  1. Eh, maybe
  2. No, because you could either go through Finset Int or Set Nat, and the defeq is different depending on which way you go

Kyle Miller (Oct 28 2024 at 20:33):

Good point re 2, that's a lot better of a reason than my justification. (And a 'no' to 2 means a 'no' to 1, since otherwise coercions aren't transitive.)

Yaël Dillies (Oct 28 2024 at 20:36):

Coercions don't have to be transitive, right? That's why we have so many CoeSomething typeclasses, no?

Kyle Miller (Oct 28 2024 at 20:50):

Yeah I suppose you're right.

If this were wired into CoeHead for example, then that would solve 2, though you could still trigger a sequence of coercions to get a coercion diamond.

Incidentally, why is Finset.instCoeTCSet a CoeTC? That's a nonstandard, since it's meant to be the transitive closure of Coe.

Notification Bot (Oct 28 2024 at 22:02):

6 messages were moved from this topic to #general > Why is the Finset->Set coercion instance CoeTC? (Was: uni... by Kyle Miller.


Last updated: May 02 2025 at 03:31 UTC