Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating polymorphic functions in Haskell

A short search didn't help me to find the answer, so I started to doubt in its existance. The question is simple. I want to create a polymorphic function, something like this:

f :: String -> String
f s = show (length s)

f :: Int -> String
f i = show i

A function defined differently for different data types is meant. Is it possible? If yes, how?

like image 690
aplavin Avatar asked Sep 14 '12 19:09

aplavin


People also ask

Does Haskell have polymorphic functions?

Polymorphism is widespread in Haskell and is a key feature of its type system. Most polymorphism in Haskell falls into one of two broad categories: parametric polymorphism and ad-hoc polymorphism.

What are polymorphic functions?

A function that can evaluate to or be applied to values of different types is known as a polymorphic function. A data type that can appear to be of a generalized type (e.g. a list with elements of arbitrary type) is designated polymorphic data type like the generalized type from which such specializations are made.

What is the difference between ad hoc and universal polymorphism?

Universal or parametric polymorphism is another type of polymorphism. Unlike ad hoc, which is based on type, universal polymorphism is type-agnostic. Ad hoc polymorphism is derived from the loose translation of “ad hoc,” which is “for this.” That means the polymorphism relates specifically to certain data types.

How do you achieve parametric polymorphism?

Parametric Polymorphism opens a way to use the same piece of code for different types. It is implemented by the use of Templates. Using Templates, the same function can be parameterized with different types of data, but this needs to be decided at compile-time itself, and hence, this polymorphism is named so.


2 Answers

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)
like image 138
Don Stewart Avatar answered Sep 28 '22 06:09

Don Stewart


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
like image 24
Satvik Avatar answered Sep 28 '22 05:09

Satvik