Zulip Chat Archive

Stream: new members

Topic: Lean typing questions


Ching-Tsun Chou (Jan 22 2025 at 02:48):

Lean's typing behavior is driving me crazy. Consider the following code:

variable (α : Type*) [inst : Fintype α] [DecidableEq α]

def Perm := α  Fin (Fintype.card α)

def hasSetPrefix (s : Finset α) (p : Perm α) : Prop :=  a  s, p.toFun a  s.card

variable (s : Finset α) (p : Perm α) in
#check (hasSetPrefix (α := α) s p)

theorem num_perms_set_prefix (s : Finset α) :
    Fintype.card { p : Perm α // hasSetPrefix (α := α) s p } = s.card.factorial * (Fintype.card α - s.card).factorial := by
  sorry

Question 1: Why is the (α := α) necessary in the #check? I found that if I drop it, Lean gets confused about the type of p.

Question 2: Lean "failed to synthesize Fintype { p // hasSetPrefix α s p }" on the subtype construction in the last theorem. Why? What is going on?

Aaron Liu (Jan 22 2025 at 02:53):

Question 1: Why is the (α := α) necessary in the #check? I found that if I drop it, Lean gets confused about the type of p.

Since you wrote (α : Type*) at the top, Lean is expecting hasSetPrefix α s p, so when you write hasSetPrefix s p, Lean tries to convert s to a type, and then gets confused when p is not a Finset.

Ching-Tsun Chou (Jan 22 2025 at 02:56):

That's a good point. The (α := α) can be replaced by α.

Ching-Tsun Chou (Jan 22 2025 at 03:02):

I used the explicit (α : Type*) because of the issues discussed in #new members > How to prove some simple combinatoric identities

Ching-Tsun Chou (Jan 22 2025 at 03:04):

So my question 1 is solved. Question 2 remains.

Aaron Liu (Jan 22 2025 at 03:04):

Question 2: Lean "failed to synthesize Fintype { p // hasSetPrefix α s p }" on the subtype construction in the last theorem. Why? What is going on?

Fintype means "I can list out all the elements of this type without duplication and without missing any (and I can prove my listing has these properties)". "Failed to synthesize" means Lean's typeclass system was not able to automatically find a way to have a Fintype for your type.
The problem is, when making a list of all the { p : Perm α // hasSetPrefix (α := α) s p }, Lean has no way of knowing if a certain Perm α should go in the list or not.
One way to fix this is by using open Classical to tell Lean to use the axiom of choice to figure out if a permuatation should be included.
Another way to solve this is by writing a docs#Decidable instance for your hasSetPrefix function, that gives an algorithm for deciding (I recommend this way).
Another way is to not use Fintype.card, but instead something like docs#Nat.card which doesn't need a Fintype instance but cannot be evaluated either.

Aaron Liu (Jan 22 2025 at 03:07):

Here's an example Decidable instance for hasSetPrefix.

instance : Decidable (hasSetPrefix α s p) := decidable_of_iff' _ (iff_of_eq <| hasSetPrefix.eq_def ..)

Aaron Liu (Jan 22 2025 at 03:08):

Alternatively, you can say abbrev hasSetPrefix instead of def hasSetPrefix and the typeclass system will unfold your definition and derive the decidability for the underlying forall statement.

Ching-Tsun Chou (Jan 22 2025 at 03:14):

Thanks for the explanations! How is abbrev different from def?

Kevin Buzzard (Jan 22 2025 at 07:47):

It's more reducible (more parts of the system will unfold it)

Ching-Tsun Chou (Jan 22 2025 at 18:58):

abbrev is not mentioned in any of the documents listed in the "Books" section here:

https://leanprover-community.github.io/learn.html

It is described in "Functional programming in Lean", but I thought I was just doing theorem proving.

Aaron Liu (Jan 22 2025 at 19:24):

The elaborator has a concept called transparency. Every definition has a transparency associated with it, and the definition will only be unfolded if it is transparent enough.
The four definition transparencies are:

@[reducible] def
@[instance] def
def and
@[irreducible] def

The four transparency modes are:

reducible : unfold reducible defs
instances : unfold reducible and instance defs
default : unfold everything except irreducible defs
all : unfold everything

abbrev is short for @[reducible] def, so typeclass inference will unfold it.
Metaprogramming in Lean has a section on transparency here.

Ching-Tsun Chou (Jan 22 2025 at 21:22):

Thanks for the explanation!


Last updated: May 02 2025 at 03:31 UTC