Custom Eq instance for Singletons

I need some guidance regarding singletons.

So, I’m trying to generate a custom Eq instance for my singletons:

type Name = [Char] 
$(singletons [d|
  newtype TVar' = TV [Char] deriving (Eq)
  data Types 
    = TCon Name [Types]
    | TVar TVar' 

  instance Eq Types where 
    (==) (TCon a xs) (TCon b ys) = 
      ((a == ['T','O','P']) && ... )
    :
    :
    :
  |])

But i can already see that this is going to be very painful to work with.

  • I have to write strings as their list representation instead of their sugated version "TOP". Otherwise I get a could not deduce SIsString [Char] error.
  • I cannot pattern match on literals, so (==) (TCon ['T','O','P'] xs) (TCon ['T','O','P'] ys) yields an error

I could of course, work with Nat instead of names, and have a structure that remembers the mappings. But I would like to avoid that. Is there a better methodology to follow?

The challenge is that "TOP" has a different representation at the term level versus the type level. At the term level, "TOP" is a String (or, more generally, any instance of IsString). At the type level, "TOP" is a Symbol, and you can’t easily create Symbol values at the term level. Somehow, we have to convince singletons to use a String-like thing at the term level and a Symbol at the type level.

This requires some advanced singletons usage, but one way to accomplish this would be to follow the advice listed in this section of the singletons README. That is, create two different versions of your data type at the term and type level:

-- Term level
data Types = TCon Text [Types] | ...

-- Type level
data PTypes = PTCon Symbol [Types] | ...

And then override singletons-th’s Template Haskell options to ensure that it promotes Types to PTypes, TCon to PTCon, etc.

3 Likes

omg thats brilliant, thank you so much! i totally forgot that main package had this documented