[Haskell-beginners] Polymorphism question from an OO-speaking newbie

Brent Yorgey byorgey at seas.upenn.edu
Mon May 4 12:47:44 EDT 2009


On Mon, May 04, 2009 at 10:34:09AM -0500, Joel Neely wrote:
> Short version: Is it possible/reasonable to define a single function
> that accepts a single string or a list of strings (in which case it
> maps the single-string "flavor" over the list)?

Short answer: no.  For the long answer (no, but sort of yes) see below. =)

> Longer version: Thus far I know that Haskell allows me to define a
> function on a single string, then define another function that maps
> the first one across a list of strings, as in:
> 
>     *Main> let quote1 s = "\"" ++ s ++ "\""
> 
>     *Main> "Quux said " ++ quote1 "foo" ++ " loudly"
>     "Quux said \"foo\" loudly"
> 
>     *Main> let quote = map quote1
> 
>     *Main> quote ["foo", "baz", "bletch"]
>     ["\"foo\"","\"baz\"","\"bletch\""]
> 
> (BTW, is it standard terminology to say that quote lifts quote1 to lists?)

There are several standard ways to say it, but that is indeed one of them.

> In the above I have different names for the two functions. OO
> languages such as Java allow me to overload quote to accept either
> String or List<String> (and return the same type). AFAICT, Haskell's
> parametric polymorphism allows me to define functions (e.g. length)
> which deal with "listness" concepts indifferent to the type contained
> by the list.

Right, and this is the key: *indifferent* to the type contained by the
list.  The implementation works in *exactly the same way* for any type
you might wish to stick in.  Java has this, too, with generics.
List<foo> is defined independently of foo; you can stick any foo in
you like and it works in the same way.

However, the overloading you're talking about is known as 'ad-hoc'
polymorphism.  It means that you can give a *different* implementation
for each type.  You can't simulate this with parametric polymorphism.
If you write a Haskell function

  foo :: a -> ...
  foo x = ...

and you want foo to behave differently depending on the type of x, you
can't do it.  There's no way in the ... to decide what to do based on
x's type; the implementation has to be the same no matter what type x
is.

However!  You can get something similar to ad-hoc polymorphism with
Haskell's type classes.  Using type classes, you could do something
like this:
 
  class Quotable q where  -- any type which is an instance of Quotable must provide 
    quote :: q -> q       -- an implementation of quote

  instance Quotable String where
    quote = quote1

  instance Quotable [String] where
    quote = map quote1

Now quote has type

  quote :: (Quotable q) => q -> q

and can be used on either Strings or lists of Strings.  Haskell will
use type inference to figure out which version of quote to use
depending on the context in which it is called.

-Brent



More information about the Beginners mailing list