Difference between revisions of "Ad-hoc polymorphism"

From HaskellWiki
Jump to navigation Jump to search
m (add 'or overloading')
Line 1: Line 1:
 
[[Category:Glossary]]
 
[[Category:Glossary]]
A value is [[polymorphism|polymorphic]] if, depending on its context, it can assume more than one type. If the possible types are limited and must be individually specified before use, this is called ad-hoc polymorphism (or overloading).
+
A value is [[polymorphism|polymorphic]] if, depending on its context, it can assume more than one type. If the value is specified separately for each type it can have, this is called '''ad-hoc polymorphism''', also known as '''overloading'''. Ad-hoc polymorphic values may be used at a limited number of pre-specified types.
   
In object-oriented languages, ad-hoc polymorphism is often called ''overloading.'' For instance, in C++, the operator '''<hask>+</hask>''' may have type (in Haskell notation) <hask>Int -> Int -> Int</hask> or <hask>String -> String -> String</hask>, and may be applied to new types provided you write a definition for it using those types as arguments. The range of possible types of '''<hask>+</hask>''' in C++ is limited to those built-in and those explicitly defined.
+
For instance, in C++, the addition operator may be used on any numeric type, like <tt>int</tt> or <tt>float</tt>, and may be applied to new types provided you write a definition for it using those types as arguments. The range of possible types of <tt>+</tt> in C++ is limited to those built-in and those for which the programmer has provided a definition. Similarly, in C, the operator <tt>+</tt> may operate on <tt>int</tt> or <tt>float</tt> or pointers. However, the programmer cannot supply their own definitions, and only the built-in types can be used.
   
  +
In Haskell, type classes are used as a mechanism for "principled overloading", i.e. ad-hoc polymorphism. For instance, the following function:
Many non-object-oriented languages use ad-hoc polymorphism too. In C, the operator '''<hask>+</hask>''' may have the types <hask>Int -> Int -> Int</hask> or <hask>Float -> Float -> Float</hask> or <hask>Double -> Int -> Double</hask> or <hask>Ptr -> Int -> Ptr</hask>. The range of possible types of <hask>+</hask> in C is limited to those built-in.
 
  +
<haskell>
  +
show :: (Show a) => a -> String
  +
</haskell>
  +
may adopt any of the following types:
  +
<haskell>
  +
Int -> String
  +
Float -> String
  +
(Maybe Int, String, Either Char Float) -> String
  +
</haskell>
  +
The types which <hask>show</hask> can adopt are precisely those which have an instance of the standard <hask>Show</hask> class defined. Each instance gives a definition of the <hask>show</hask> function to be used when the types match. Unlike in C++ function overloading, Haskell also allows overloaded ''values'', like <hask>maxBound</hask>, that adopt a different value based on their type (e.g. <hask>maxBound :: Bool</hask> is equal to <hask>True</hask>, while <hask>maxBound :: Int</hask> may be <hask>2147483647</hask>).
   
 
Contrast ad-hoc polymorphism with [[parametric polymorphism]]: e.g. the function <hask>length :: [a] -> Int</hask> may be applied to lists of ''any'' type, but has only one definition which it uses regardless of which type it adopts.
In Haskell, ad-hoc polymorphism is achieved by type classes. For instance, the function <hask>show</hask> may have type of the form <hask>Int -> String</hask> or <hask>Float -> String</hask> or <hask>(Maybe Int, String, Either Char Float) -> String</hask> depending on its context, but the possible types of <hask>show</hask> are limited. The user must ''specify'' the type <hask>show</hask> will take by defining the type of its first argument as an instance of <hask>Show</hask>. (This is reflected in its signature <hask>show :: Show a => a -> String</hask>.)
 
 
Contrast ad-hoc polymorphism with [[parametric polymorphism]] of the function <hask>length :: [a] -> Int</hask>. <hask>length</hask> may be applied to lists of ''any'' type--that is, may take on an unlimited number of types (of the form <hask>[a] -> Int</hask>)--and the user may apply it to any list without needing to specify the type beforehand.
 

Revision as of 18:26, 30 April 2012

A value is polymorphic if, depending on its context, it can assume more than one type. If the value is specified separately for each type it can have, this is called ad-hoc polymorphism, also known as overloading. Ad-hoc polymorphic values may be used at a limited number of pre-specified types.

For instance, in C++, the addition operator may be used on any numeric type, like int or float, and may be applied to new types provided you write a definition for it using those types as arguments. The range of possible types of + in C++ is limited to those built-in and those for which the programmer has provided a definition. Similarly, in C, the operator + may operate on int or float or pointers. However, the programmer cannot supply their own definitions, and only the built-in types can be used.

In Haskell, type classes are used as a mechanism for "principled overloading", i.e. ad-hoc polymorphism. For instance, the following function:

show :: (Show a) => a -> String

may adopt any of the following types:

Int -> String
Float -> String
(Maybe Int, String, Either Char Float) -> String

The types which show can adopt are precisely those which have an instance of the standard Show class defined. Each instance gives a definition of the show function to be used when the types match. Unlike in C++ function overloading, Haskell also allows overloaded values, like maxBound, that adopt a different value based on their type (e.g. maxBound :: Bool is equal to True, while maxBound :: Int may be 2147483647).

Contrast ad-hoc polymorphism with parametric polymorphism: e.g. the function length :: [a] -> Int may be applied to lists of any type, but has only one definition which it uses regardless of which type it adopts.