bimmo
bimmo

Reputation: 395

How to define superclass?

How does one define a super class in Haskell? My situation is that I have defined a class StringHashed that maps members to their names as a String. I wish to implement, en mass, all t from Show t by making the string name simply return show t. Am I right in saying that StringHashed is now a superclass of Show? Here is what I would like to be able to write:

class StringHashed t where
    stringHash :: t -> String

instance Show t => StringHashed t where
    stringHash = show

But Haskell complains about an invalid instance declaration. I have also tried instance StringHashed (Show t) and other syntactical dribble; none have worked for me. I have also read a proposal on the GHC wiki that provides no solution. This is the one. I have concern about using -XFlexibleInstances simply because it is not default. Is there a proper way to achieve a general instance declaration? Or am I being too demanding of Haskell's type system?

Upvotes: 4

Views: 653

Answers (1)

Ørjan Johansen
Ørjan Johansen

Reputation: 18189

Haskell superclasses cannot be added after the fact - they need to be mentioned in the subclass's declaration. And defining an instance like you do in the question, while possible with extensions, can create subtle overlap problems.

FlexibleInstances itself is not the problem - it's one of GHC's most innocuous extensions. The problem is that GHC's instance lookup method means that

instance Show t => StringHashed t where ...

defines this instance to hold for all types t - the Show t restriction is only an afterthought checked after lookup. So it will overlap with all other instances you can make, and while there is an extension OverlappingInstances to allow this, it is considered somewhat dubious to use.

However GHC has a feature DefaultSignatures, which is designed for use cases similar to yours:

{-# LANGUAGE DefaultSignatures #-}

class StringHashed t where
    stringHash :: t -> String
    default stringHash :: Show t => t -> String
    stringHash = show

instance StringHashed Int

This allows you to write a default for the method which only works for some instance types. Note however, that you still need to write an actual instance declaration for each type - but its body can be empty.

Upvotes: 11

Related Questions