Zulip Chat Archive

Stream: new members

Topic: Need help to understand strict implicit vs implicit


Kevin Cheung (Feb 01 2024 at 23:34):

There are a few theorems in Finset that contain strict implicits. I am not quite getting what the documentation about strict implicit says: "Strict-implicit binder. In contrast to { ... } regular implicit binders, a strict-implicit binder is inserted automatically only when at least one subsequent explicit parameter is specified."

Suppose I have something simple like the following:

def bar m :  { n :  } (q : ) (_ : Fin m) (_ : Fin n)  := m * n * q

How would strict implicit around m here behave differently as opposed to being just an implicit?

Kyle Miller (Feb 01 2024 at 23:49):

Let's compare strict implicit and regular implicits:

def bar m :  { n :  } (q : ) (_ : Fin m) (_ : Fin n)  := m * n * q
def bar' {m : } { n :  } (q : ) (_ : Fin m) (_ : Fin n)  := m * n * q

/-
Using parentheses forces `#check` to show you the type of the expression,
rather than giving a declaration-style signature for a constant.
-/
#check (bar)
-- bar : ⦃m : ℕ⦄ → {n : ℕ} → ℕ → Fin m → Fin n → ℕ
#check (bar')
-- bar' : ℕ → Fin ?m.9034 → Fin ?m.9035 → ℕ
#check @bar'
-- @bar' : {m n : ℕ} → ℕ → Fin m → Fin n → ℕ
#check bar 1
-- bar 1 : Fin ?m.9037 → Fin ?m.9038 → ℕ
#check bar' 1
-- bar' 1 : Fin ?m.9055 → Fin ?m.9056 → ℕ

Kyle Miller (Feb 01 2024 at 23:50):

Notice that bar keeps the m argument, but bar' immediately turns it into a metavariable (?m.9034 here).

Kevin Cheung (Feb 01 2024 at 23:51):

Interesting. So why do #check bar 1 and #check bar' 1 seem to be the same?

Kyle Miller (Feb 01 2024 at 23:53):

They're both filling in q with 1, so in both cases m is treated as an implicit.

Kevin Cheung (Feb 01 2024 at 23:54):

So in this case, there is really no practical reason to use strict implicit?

Kyle Miller (Feb 01 2024 at 23:54):

Strict implicits behave like regular implicits so long as an explicit argument is provided after it.

Kyle Miller (Feb 01 2024 at 23:55):

If you want to be able to pass bar around while preserving that m could be anything, then strict implicits are useful.

Kevin Cheung (Feb 01 2024 at 23:56):

Let me if I understand this. Once Lean assigns a metavariable (e.g. ?m.9034), it's fixed for the rest of the code? But having it as m means it can change depending on who accepts bar as an argument?

Kyle Miller (Feb 01 2024 at 23:57):

Yeah, exactly.

Kyle Miller (Feb 01 2024 at 23:57):

Many times, rather than strict implicits, you can make it be an explicit argument and then pass _ for that argument when you want to simulate regular implicits.

Kevin Cheung (Feb 01 2024 at 23:58):

Thank you. I wish your explanation could be found in a book somewhere.

Kyle Miller (Feb 01 2024 at 23:58):

I don't have the best sense of when strict implicits are useful, but they can be useful for properties like ∀ ⦃x⦄, x ∈ s → x ∈ t, since then x stays free until you pass in the "actual" data, the proof of x ∈ s

Kyle Miller (Feb 01 2024 at 23:59):

With ∀ x ∈ s, x ∈ t notation (available in mathlib), maybe it should make the x be a strict implicit, but for now it's explicit. (That is, the current meaning is ∀ x, x ∈ s → x ∈ t.)

Kevin Cheung (Feb 02 2024 at 00:01):

I see. Now, it makes sense.

Eric Rodriguez (Feb 02 2024 at 11:36):

Kyle Miller said:

With ∀ x ∈ s, x ∈ t notation (available in mathlib), maybe it should make the x be a strict implicit, but for now it's explicit. (That is, the current meaning is ∀ x, x ∈ s → x ∈ t.)

I think for these binders it'd be nice to have these be configurable to be whatever level of implicitness is right

Kevin Cheung (Feb 02 2024 at 11:46):

How would such configurability look like?

Eric Rodriguez (Feb 02 2024 at 11:52):

maybe something crazy like ∀ ({x} ∈ s), x ∈ t


Last updated: May 02 2025 at 03:31 UTC