
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