Function overloading is very common in many programming languages like C# but most of the languages that I have used only support overloading based on function arguments. For example in C# there are several overloads on the String.IndexOf function where each overload differs in what argument type it accepts.
This overloading support doesn’t extend to function return types. If an additional overload is added (bool String.IndexOf(char)) that returns true if the character is found in the string the compiler will give an error like “Type ‘String.IndexOf’ already defines a member called ‘IndexOf’ with the same parameter types”.
The Haskell Way
Haskell supports both function argument type and return type overloading using type classes.
Given two functions indexOfExists and indexOfPos.
indexOfPos value str = case elemIndex value str of Just i -> i Nothing -> -1 indexOfExists value str = case elemIndex value str of Just _ -> True Nothing -> False
I can create a type class which defines an indexOf function and add both indexOfPos and indexOfExists to this class.
class StringOps a where indexOf :: Char -> String -> a instance StringOps Int where indexOf value str = indexOfPos value str instance StringOps Bool where indexOf value str = indexOfExists value str
Now when I use the indexOf method Haskell will figure out whether to use indexOfExists or indexOfPos based on the return type.
*Main> indexOf 'e' "matthew" :: Bool True *Main> indexOf 'e' "matthew" :: Int 5
Real World Use Case
This functionality is used beautifully in the Text.Regex.Posix module. This module contains regular expression functions and in particular exposes the =~ operator. This operator lets you match a regex pattern against a string and its behavior is overloaded based on its return type. This is useful since whether you want to know if the regex matches, what the first match is or get a list of all matches you can just use the =~ operator and the return value type will match the code you write. Here are some examples of output from the =~ operator based on return type:
*Main Text.Regex.Posix> "mississippi" =~ "i(s|p)" :: Bool True *Main Text.Regex.Posix> "mississippi" =~ "i(s|p)" :: String "is" *Main Text.Regex.Posix> "mississippi" =~ "i(s|p)" :: Int 3 *Main Text.Regex.Posix> "mississippi" =~ "i(s|p)" :: (String,String,String) ("m","is","sissippi") *Main Text.Regex.Posix> "mississippi" =~ "i(s|p)" :: (Int,Int) (1,2)