CodyBugstein
CodyBugstein

Reputation: 23322

Can't make String an instance of a class in Haskell

I'm playing around trying to understand classes in Haskell. I wrote a silly few lines of code to get the hang of it. I wrote a class called Slang that has one function. When I make Integer an instance of my class, it works fine. But when I make String an instance of my class it won't compile. I've been fidgeting with the program based on what the error output tells me but to no avail. I have idea why it work...

Here is the code followed by the error:

module Practice where

class Slang s where
    slangify :: s -> String

instance Slang Integer where
    slangify int = "yo"

instance Slang String where  -- When I take this segment out, it works fine
    slangify str = "bro"

ERROR:

Prelude> :load Practice
[1 of 1] Compiling Practice         ( Practice.hs, interpreted )

Practice.hs:9:10:
    Illegal instance declaration for `Slang String'
      (All instance types must be of the form (T t1 ... tn)
       where T is not a synonym.
       Use -XTypeSynonymInstances if you want to disable this.)
    In the instance declaration for `Slang String'
Failed, modules loaded: none.
Prelude>

Upvotes: 9

Views: 846

Answers (2)

CodyBugstein
CodyBugstein

Reputation: 23322

I did some research in my Haskell literature (aka my current Bible) and found an example that effectively solves my problem.

Basically, in this workaround you set Char to be an instance of the class (in the book's example it's called Visible) and then you can set [chars] aka a String, to be an instance of the class as well ONLY WITH the stipulation that the type variable chars be an instance of `Visible'. It's easier to understand if you look at the code below:

module Practice where

class Visible a where
  toString :: a -> String
  size :: a -> Int

instance Visible Char where
  toString ch = [ch]
  size _ = 1

instance Visible a => Visible [a] where
  toString = concat . map toString
  size = foldr (+) 1 . map size

My GHCi load and function call:

*Practice> :l Practice
[1 of 1] Compiling Practice         ( Practice.hs, interpreted )
Ok, modules loaded: Practice.
*Practice> size "I love Stack!"
14
*Practice>

Eureka!

Upvotes: 5

hugomg
hugomg

Reputation: 69944

The problem is that String is not a base type like Integer. What you are trying to do is actually

instance Slang [Char] where
    slangify str = "bro"

However, Haskell98 forbids this type of typeclass in order to keep things simple and to make it harder for people to write overlapping instances like

instance Slang [a] where
    -- Strings would also fit this definition.
    slangify list = "some list"

Anyway, as the error message suggests, you can get around this restriction by enabling the FlexibleInstances extension.

Upvotes: 14

Related Questions