Zulip Chat Archive

Stream: new members

Topic: joining typeclasses


ooovi (Dec 13 2024 at 13:28):

Hello!

I'm in a situation where I'm making a lot of arguments about types that are members of a number of typeclasses and have some other common properties. Currently, I spell all of them out in all my type signatures. I was thinking to make a type class that contains all the properties I need, but I fail to make instance inference work. Am I walking in the wrong direction?

Here's what I tried. So I make a typeclass for my (exemplary) properties:

class MeFinClass (type : Type*) (N : Nat) where
  fin : Fintype type
  card : Fintype.card type = N

Next, I want inference of the Fintype instance for type:

instance hm [t : MeFinClass α N] : Fintype α where
  elems := t.fin.elems
  complete := t.fin.complete

but I get in trouble:

cannot find synthesization order for instance @hm with type
  {α : Type u_1}  {N : }  [t : MeFinClass α N]  Fintype α
all remaining arguments have metavariables:
  MeFinClass α ?N

I don't understand what that means, and maybe I should do a different thing alltogether?

Matt Diamond (Dec 13 2024 at 21:06):

I suspect this is a case where you need to mark N as an outParam or a semiOutParam, but I'm not sure which (see docs#outParam and docs#semiOutParam)

the idea is that it lets you tell Lean the order in which typeclass params should be resolved... so in this case we're telling Lean "don't worry about N until you figure out what α is, and then just use whatever N you find first"

Matt Diamond (Dec 13 2024 at 21:07):

it looks like either of them work here, but I don't know enough to tell you which is the "correct" one

Matt Diamond (Dec 13 2024 at 21:08):

btw when I say mark it as an outParam I mean something like this:

import Mathlib

class MeFinClass (type : Type*) (N : outParam Nat) where
  fin : Fintype type
  card : Fintype.card type = N

instance hm [t : MeFinClass α n] : Fintype α where
  elems := t.fin.elems
  complete := t.fin.complete

Eric Wieser (Dec 13 2024 at 21:17):

Or the shorter

class MeFinClass (type : Type*) (N : outParam Nat) extends Fintype type where
  card : Fintype.card type = N

which avoids needing to write the instance manually

Matt Diamond (Dec 13 2024 at 21:17):

ah, there's always a better solution :)

ooovi (Dec 14 2024 at 08:51):

Sweet, thank you both! Quick follow-up, I read somewhere that multiple inheritance is also possible for typeclasses using the same syntax as for structures, but the following won't work:

class MeeFinClass (type : Type*) (N : outParam Nat) extends (Fintype type), (DecidableEq type) where
  card : Fintype.card type = N

gives complaints about the second extended class:

expected structure

Ruben Van de Velde (Dec 14 2024 at 08:59):

Try without the parentheses

Eric Wieser (Dec 14 2024 at 09:12):

DecidableEq is not a structure

Eric Wieser (Dec 14 2024 at 09:22):

This works:

import Mathlib

class MeeFinClass (type : Type*) (N : outParam Nat) extends Fintype type where
  [toDecidableEq : DecidableEq type]
  card : Fintype.card type = N

attribute [instance] MeeFinClass.toDecidableEq

Last updated: May 02 2025 at 03:31 UTC