idiom for different implementations of same idea

Dr. Harald Holtmann holtmannh@t-online.de
Fri, 2 Aug 2002 01:54:04 +0200


Hal Daume III writes:
> Hi all,
>
> I'm looking for some advice on what's the cleanest way to implement
> something.  The basic idea is that I have a task to solve, T.  There are
> many steps to solving this task, but they can be broken down into a small
> list of elementary steps:
>
>   - prepareData
>   - initialize
>   - doThingOne
>   - doThingTwo
>   - getResults
>

In similar situations, especially if there is more than one useful way to
use the various parts of an algorithm, I used often prefer existentials:

data Model = forall markup table alignments. Model
	{
	   prepareData :: Data () -> Data markup,
	   initialize  :: Data markup -> ST s table,
	   doThingOne  :: Data markup -> table -> ST s alignments,
	   doThingTwo  :: Data markup -> alignments -> ST s table,
	   getResults  :: Data markup -> table -> alignments -> String
	}

So each model-module only needs to export one model record and the standard
algorithm can be implemented easily: (simplified, not checked for stupid
errors)

execModel model data =
	let mark = prepareData model $ data in
 	      runST $ do tab <- (initialize model) mark
			     align <- (doThingOne model) mark tab
			     res <- (doThingTwo model) mark align
			     return $ (getResults model) mark res align

Of course, by using existentials, no model internal type can escape.

> Now, I want in my executable my user to be able to say "-model=0" and so
> on in the command line and for it to use the appropriate model.  Each of
> these models will go in a separate module.

This way one can even program a top-level like

	doForAll data = map (\m -> execModel m data) [model0, model1, model2, ...]

which is rather useful.

Regards,
	Harald