FiniteMap: modifyFM

Hal Daume III hdaume@ISI.EDU
Wed, 19 Jun 2002 07:58:24 -0700 (PDT)


Hi all,

On 19 Jun 2002, Ketil Z. Malde wrote:

> Alastair Reid <reid@cs.utah.edu> writes:
> 
> OTOH, I find I define classes very sparingly in my own programming.
> Comong from an OO world I started out with a desire to create classes
> for just about anything, but in practice, it rarely seems necessary.
> So while it still can be useful or desirable, it just doesn't get
> done. 

There are always (as I see it) three options:

  - Use a class              -- i.e., Set s a => empty :: s a
  - Use a "qualified" name   -- i.e., S.empty :: Set a
  - Use a name with a qualifier tacked on manually
                             -- i.e., emptySet :: Set a

Going from the bottom up, we have the least complex up to the most
complex.  The qualified name option has as a problem (pointed out
recently, I don't remember whom by) the issue of collection modules.

I think the general policy I've used is: if there is already a class into
which it fits, put it in a class; otherwise, put use the third option.

This is largely due to the fact that the Prelude was so well
designed.  Usually, whatever my data type, the operations I wish to
perform over it fall into some function from the prelude, most usually:

  map, fold, filter (though less often filter than the other two),
  mapAccum, mapM, foldM, lookup, find, and maybe a few otheres

(For instance, I wrote all of these functions to work on top of the HsSyn
library of Haskell syntax to easy some work I was doing.)

The problem is that the prelude is so well put together than I rarely need
more functions than it provides for my datatypes (at least, more *general*
functions; obviously each data type has data-specific functions, but I'm
glossing over that now).  The problem this leaves me with is that it's
taken all the good names.  So I end up calling the functions on my trees:

  tmap, tfold, tlookup, etc...

(Though occasionally I use fmap in Functor instead of tmap.)

This extends beyond collections; I recently needed a datatype (silly as it
may sound), which is |R U {+oo, -oo}, with addition defined as:

  -oo + _ = -oo
   oo + _ =  oo
    r + r = r + r

(obviously associative).

That is, -oo always wins out, even over +oo, but otherwise it's just
"normal" addition.  The problem is, I either had to use some strange
symbol like $+ for addition, or make it an instance of Num, without any of
the other operations (I opted for the latter).

I've been considering both (a) using Ashley's prelude, which seems to
adopt a one-op-per-class mentality or (b) learning more about Clean.

I know there was some talk a while back about having a "beginners" prelude
(similar to what we have now) and an "advanced" prelude, supposedly
similar to Ashley's.  I would definately be in favor of this.  Whether we
call it class Add or class Group is largely irrelevant to me (I tend to
find class names to be fairly superfluous anyway).

I think the only classes I ever write (or derive) instances of are:
  Eq, Ord, Show, Read (rarely), Num, Binary, Fractional (rarely), Hash,
DeepSeq, Monad (rarely), Functor (rarely)

Okay, well I guess that's almost all of them.  But according to a quick
grep, the only onces I write frequently are:
  Eq, Ord, Show, Num

Moreover, the only *classes* I've ever defined (other than for toy little
tests with classes) are:
  Hashable, Container

Though the functions I frequently want to override (listed above) fall
into none of these.

So...yeah...I've kind of lost my train of thought, but I think that the
problem I've frequently had is that I want to use the names the prelude
uses, but can't.  :).

That's all.

 - Hal