Zulip Chat Archive

Stream: new members

Topic: Implementing instances for inductive types


Shubham Kumar 🦀 (he/him) (Mar 24 2024 at 11:11):

How does one implement Eq instance for an inductive type

inductive Token : Type :=
  | Id : Token -- | Terminal Symbol
  | Ident : String -> Token -- | Token contains a String Identifier
  | Number : Int -> Token -- | Token contains an Int value
  | If_Symbol : Token
  | Then_Symbol : Token
deriving Eq

deriving Eq doesn't work

default handlers have not been implemented yet, class: 'Eq' types: [Token]

Yaël Dillies (Mar 24 2024 at 11:16):

docs#Eq is defined for every type already

Shubham Kumar 🦀 (he/him) (Mar 24 2024 at 11:18):

so deriving Eq should not show that error message, is it an incorrect way to use it?

Yaël Dillies (Mar 24 2024 at 11:18):

Eq is not a typeclass, so it doesn't make any sense to use deriving Eq

Shubham Kumar 🦀 (he/him) (Mar 24 2024 at 11:20):

oh ok, so I can just use = and it would implicitly search for the instance?

Yaël Dillies (Mar 24 2024 at 11:20):

There is no instance because there is no typeclass!

Yaël Dillies (Mar 24 2024 at 11:20):

Have you clicked here? :point_right: docs#Eq :point_left:

Yaël Dillies (Mar 24 2024 at 11:21):

You will see what Eq is, and how it is not the same as Haskell's Eq (which is more like docs#BEq instead)

Eric Wieser (Mar 24 2024 at 11:24):

The answer here is possibly that you meant deriving BEq or deriving DecidableEq

Shubham Kumar 🦀 (he/him) (Mar 24 2024 at 11:26):

ok, soEq is an inductive type which consumes 2 Types and returns a Prop while BEq is typeclass which defines the beq function that consumes 2 Types (but of the same universe because it is a typeclass in that universe? I don't know why Type u is specified) and returns a Bool Type which is an inductive Type

Yaël Dillies (Mar 24 2024 at 11:26):

No, it doesn't consume two types. Instead it consumes one type α and two elements of that type

Shubham Kumar 🦀 (he/him) (Mar 24 2024 at 11:27):

Thanks! I didn't have (still don't) any understanding of Eq then

Yaël Dillies (Mar 24 2024 at 11:29):

When I write 0 = 1, this is notation for @Eq Nat 0 1. So α := Nat

Shubham Kumar 🦀 (he/him) (Mar 24 2024 at 11:30):

oh not that part, I don't know what is the difference between Eq and BEq I was assuming both are typeclasses, which it isn't and I don't have an image of how they are related

Yaël Dillies (Mar 24 2024 at 11:31):

The truth is that they are not

Yaël Dillies (Mar 24 2024 at 11:31):

Eq is mathematical equality. BEq is just a typeclass that gives you access to the == notation

Yaël Dillies (Mar 24 2024 at 11:32):

If you want to state that == corresponds to mathematical equality (namely ∀ a b, a = b ↔ a == b), you use docs#LawfulBEq

Shubham Kumar 🦀 (he/him) (Mar 24 2024 at 11:35):

Interesting, thanks you have given me a lot to think about.

For now, I think deriving BEq should work and probably I don't need to derive an instance

Shubham Kumar 🦀 (he/him) (Mar 27 2024 at 07:24):

another stupid question, even after deriving DecidableEq it seems like Token doesn't have the DecidableEq instance

def pSym {s : Type} [DecidableEq s] (a : s) : Parser s s :=
  Parser.P (λ inp =>
    match inp with
    | s :: ss => if a = s then [(s, ss)] else []
    | _ => [])

inductive Token : Type :=
  | Id : Token -- | Terminal Symbol
  | Ident : String -> Token -- | Token contains a String Identifier
  | Number : Nat -> Token -- | Token contains an Int value
  | If_Symbol : Token
  | Then_Symbol : Token
deriving DecidableEq, BEq

def pIdent := pSym Id

error

error: typeclass instance problem is stuck, it is often due to metavariables
  DecidableEq ?m.4178

Henrik Böving (Mar 27 2024 at 07:34):

You want to write pSym Token.Id

Shubham Kumar 🦀 (he/him) (Mar 27 2024 at 07:35):

Thanks! I knew it was something stupid

Shubham Kumar 🦀 (he/him) (Mar 27 2024 at 07:58):

so in the previously stated messages (not sure if it would be clear) I was trying to get to a place where after defining my token Inductive type I can define a concrete equality where Token.Id = Token.Ident "" should be true but the automatic derivation leads to false

inductive Token : Type :=
  | Id : Token -- | Terminal Symbol
  | Ident : String -> Token -- | Token contains a String Identifier
  | Number : Nat -> Token -- | Token contains an Int value
  | If_Symbol : Token
  | Then_Symbol : Token
deriving DecidableEq, BEq

#eval Token.Id = Token.Ident "" -- | should be true

image showing false
Screenshot-from-2024-03-27-13-26-46.png

How to I go about defining equality if I want it to be true?

Markus Schmaus (Mar 27 2024 at 18:40):

The direct answer to your question is docs#Quotient. Given an equivalence relation, this creates a new type for which this equivalence relation defines Eq equality. But If your goal is simply Token.Id = Token.Ideny "", the simpler solution would be to define the former in terms of the latter.

Kyle Miller (Mar 27 2024 at 18:50):

Make sure not to derive both DecidableEq and BEq. You get BEq for free from DecidableEq.

And also Markus's suggestion is the right one for overriding the equality for a type. Quotients are the way you create a type from another type with a looser Eq. (This is not done with typeclasses.) I suppose you could define BEq on the original type to correspond exactly to the Eq on the quotient type — I'm not sure how much people have explored that design pattern.

Shubham Kumar 🦀 (he/him) (Mar 27 2024 at 21:37):

I would like to do the simple thing but first maybe waste time on understanding what quotient is, I found something related to quotient types but if there are easier ways to approach this I'll be happy to look looking at Wikipedia.

Thanks for the help!


Last updated: May 02 2025 at 03:31 UTC