[Fwd: Re: type class VS struct/functor]
John Hughes
rjmh@cs.chalmers.se
Wed, 23 Jan 2002 15:01:12 +0100 (MET)
The advantage of functors shows up when you need to have multiple
implementations of a module for a type. For instance, suppose you
want to implement a set, and you write the functors (OCaml below):
...
Now, suppose you want two kinds of sets of string, one of which is
case-sensitive and one of which is not. You can easily do this with
functors like so
module SensitiveCase =
struct
type t = string
let eq s s' = (s = s')
end
module InsensitiveCase =
struct
type t = string
let eq s s' = (String.lowercase s) = (String.lowercase s')
end
module SensitiveSet = Set(SensitiveCase)
module InsensitiveSet = Set(InsensitiveCase)
Each of these Set types takes a string, but the membership test is
different. This is an annoying case in Haskell, because you can make a
String a member of the Eq typeclass in only one way.
Of course, you can always define
newtype CaseInsensitiveString = CaseInsensitive String
whereupon you can define an Eq instance that ignores case. Maybe this isn't
common Haskell style, but it does have many advantages. In particular, the
type-checker now checks that you don't pass a case sensitive string where an
insensitive one is expected, or vice versa, and this should help catch bugs.
I've begun to use this style more, particularly when using QuickCheck. There I
define a new type when I want a different distribution of test data from the
default. I've found it's error-prone to specify which distribution to use
explicitly; much better to let the type-checker figure it out.
John