
David,
I had to bring up a parenthetical from your message because I think it
is often a point of confusion:
2008/11/17 David Leimbach
(Would it then be fair to equate a Haskell class to a Java Interface, but not to a Java class?)
This is a dangerous direction to go, because while there are some analogies, going this direction leads to many mistakes. A typeclass is similar to an interface, in that it defines the operations on some object, and you can call functions that use that typeclass polymorphically over any instance. But in the OOP model, interfaces are also a form of existential quantification. If I have an IPrintable object, I can put it on a list of IPrintables:
// psuedo-java: List<IPrintable> foo(List<IPrintable> tail) { String x = "hello"; // assume String is an instance of IPrintable return List.cons(x, tail); }
But in Haskell, this function doesn't typecheck:
foo :: Show a => [a] -> [a] foo xs = "hello" : xs
The type of "foo" says that its argument is a homogenous list of *some* instance of Show, but it doesn't specify which one. Of course, in Haskell you can make this work with existential types:
data AnyShow = forall a. Show a => ExistentialShow a foo2 :: [AnyShow] -> [AnyShow] foo2 xs = ExistentialShow "hello" : xs
foo3 :: Show a => [a] -> [AnyShow] foo3 xs = foo2 (map ExistentialShow xs)
There are a few other differences; for example,
poly :: Num a => a poly = fromInteger 1
The person *calling* poly determines what instance of Num they want returned; in OOP, poly would have to be called with a "factory" as an argument that told it how to construct the instance of the Num interface that the caller wants. This generalizes to code that would be much more difficult to write in an OOP style; consider:
poly2 :: Num a => a -> a poly2 x = x + 1 -- in Haskell, 1 here is implicitly 'fromInteger 1'
This is surprisingly hard to write in an OOP language, and almost certainly uglier than the Haskell solution. Either the arguments to plus have to be polymorphic, which is really difficult, or you need a special version of every operator that takes an Integer instead of the class in question, or you need some way to query the class for a factory which builds an instance of the class. In Haskell, (+) specifies that the arguments must be the same type, unlike the OOP solution where one argument is given privledged status as the method receiver. -- ryan