Re: type classes vs. multiple data constructors

2003-02-17 Thread Andrew J Bromage
G'day.

On Mon, Feb 17, 2003 at 01:44:07AM -0500, Mike T. Machenry wrote:

  I was wondering if it's better to define them as type classes with the
 operations defined in the class. What do haskellian's do?

I can't speak for other Haskellians, but on the whole, it depends.

Here's the common situation: You have a family of N abstractions.  (In
your case, N=2.)  The abstractions are similar in some ways and
different in some ways.  The most appropriate design depends largely
on what those similarities and differences are.

From your definitions, it seems clear that there is some common
structure.  That suggests that a vanilla type class solution may
not be appropriate, because type classes do not directly support
common structure, only related operations.

Your solution wasn't bad:

 data PlayerState =
   FugitiveState {
 tickets :: Array Ticket Int,
 fHistory :: [Ticket] } |
   DetectiveState {
 tickets :: Array Ticket Int,
 dHistory :: [Stop] }

If the operations on the tickets field are different, or the
algorithms which operate on PlayerState are different for the
FugitiveState case and the DetectiveState case, this may be a good
design, because by not sharing structure, you're explicitly denying
any similarity (i.e. just because look the similar, that doesn't mean
they are similar).

If they are similar, then this may not be an appropriate design.
Ideally, you want to use language features and/or idioms which expose
the similarities (where they exist) and the differences (where they
exist).

Here's one design where the structural similarity is explicit:

data PlayerState
  = PlayerState {
tickets :: Array Ticket Int,
role:: RoleSpecificState
}

data RoleSpecificState
  = FugitiveState  { fHistory :: [Ticket] }
  | DetectiveState { dHistory :: [Stop] }

Depending on how similar the operations on the RoleSpecificState are
(say, if they are related by a common type signature, but have little
code in common), or if you want a design which is extensible to other
kinds of player (possibly at dynamic-link time) you may prefer to use
type classes to implement the role-specific states instead:

-- Warning: untested code follows

class RoleSpecificState a where
{- ... -}

data FugitiveState = FugitiveState { fHistory :: [Ticket] }

instance RoleSpecificState FugitiveState where
{- ... -}

data DetectiveState = DetectiveState { fHistory :: [Ticket] }

instance RoleSpecificState DetectiveState where
{- ... -}

data PlayerState
  = forall role. (RoleSpecificState role) =
PlayerState {
tickets :: Array Ticket Int,
role:: role
}

(If you know anything about design patterns, you may recognise this as
being similar to the Strategy pattern.  This is no accident.)

It's hard to say what is the most appropriate design without looking at
the algorithms and operations which act on the PlayerState type and
analysing their similarities and differences.

 Oh and if I say
 Instance Foo Baz where
   ...
 
 and only define a few of the operations in Foo... bdoes Baz take on some
 default methods?

If you've declared default methods, yes.

Cheers,
Andrew Bromage
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell



type classes vs. multiple data constructors

2003-02-16 Thread Mike T. Machenry
I have a type that is as follows:

data PlayerState =
  FugitiveState {
tickets :: Array Ticket Int,
fHistory :: [Ticket] } |
  DetectiveState {
tickets :: Array Ticket Int,
dHistory :: [Stop] }

I have a few functions that act on PlayerState.

move :: PlayerState - PlayerState
move DetectiveState ... =
move FugitivieState ... =

 I was wondering if it's better to define them as type classes with the
operations defined in the class. What do haskellian's do? Oh and if I say
Instance Foo Baz where
  ...

and only define a few of the operations in Foo... bdoes Baz take on some
default methods?

- mike
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell