[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