My First Introduction to Haskell Extensions: FlexibleInstances

I’ve been tinkering with Haskell lately, and I came across an odd issue. Let’s say I want to create a class that takes Integers, Characters, and Strings and returns an Integer.

class Something a where
  doSomething :: a -> Integer

instance Something Integer where
  doSomething x = 1

instance Something Char where
  doSomething x = 2

instance Something [Char] where
  doSomething x = 3

Trying to load this into the interpreter (or compiling it) results in the an error on the String ([Char])

Illegal instance declaration for `Something [Char]'
  (All instance types must be of the form (T a1 ... an)
  where a1 ... an are type *variables*,
  and each type variable appears at most once in the instance head.
  Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Something [Char]'

This cryptic message essentially means that I can’t make [Char] an instance of the Something class, but I could make [a] one (a list containing any type)

instance Something [a] where
  doSomething x = 3

However that stinks because then I have to do a lot more work to differentiate between a list of characters (i.e. Strings) and a list of integers.

The error message mentions a way to disable that check, and the helpful guys at #haskell gave me a hand.

If you put this at the top of your source file:

{-# LANGUAGE FlexibleInstances #-}

you end up telling Haskell to load the extension FlexibleInstances which allows you to differentiate between lists of characters, integers, or whatever else. Which allows you to load in:

-- in file TestingTypes.hs
{-# LANGUAGE FlexibleInstances #-}

class Something a where
  doSomething :: a -> Integer

instance Something Integer where
  doSomething x = 1

instance Something Char where
  doSomething x = 2

instance Something [Char] where
  doSomething x = 3

-- in ghci:
Prelude> :l TestingTypes.hs
[1 of 1] Compiling TestingTypes     ( TestingTypes.hs, interpreted )
Ok, modules loaded: TestingTypes.
*TestingTypes> doSomething 1
1
*TestingTypes> doSomething 'c'
2
*TestingTypes> doSomething "foo"
3

Nothing ground breaking, but I thought I’d pass this tidbit along.