Creating polymorphic functions in Haskell

Here is how you can achieve something similar using type families.

Well if you have same return types then you can achieve the behaviour without using type families and just using type classes alone as suggested by Don.

But it is better to use type families when you want to support more complex adhoc polymorphism, like different return types for each instance.

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE TypeFamilies #-}

class F a where
    type Out a :: * 
    f :: a -> Out a

instance F String where  
    type Out String = String
    f = show . length

instance F Int where 
    type Out Int = String 
    f = show 

instance F Float where 
    type Out Float = Float
    f = id  

In ghci

*Main> f (2::Int)
"2"

*Main> f "Hello"
"5"

*Main> f (2::Float)
2.0

There are two flavors of polymorphism in Haskell:

  • parameteric polymorphism; and
  • bounded polymorphism

The first is the most general -- a function is parametrically polymorphic if it behaves uniformly for all types, in at least one of its type parameters.

For example, the function length is polymorphic -- it returns the length of a list, no matter what type is stored in its list.

length :: [a] -> Int

The polymorphism is indicated by a lower case type variable.

Now, if you have custom behavior that you want to have for a certain set of types, then you have bounded polymorphism (also known as "ad hoc"). In Haskell we use type classes for this.

The class declares which function will be available across a set of types:

class FunnyShow a where
    funnyshow :: a -> String

and then you can define instances for each type you care about:

instance FunnyShow Int where
    funnyshow i = show (i+1)

and maybe:

instance FunnyShow [Char] where
   funnyshow s = show (show s)