[Haskell-cafe] seems like I'm on the wrong track

Michael Mossey mpm at alumni.caltech.edu
Wed Dec 2 10:55:01 EST 2009



Michael P Mossey wrote:
> Perhaps someone could either (1) help me do what I'm trying to do, or 
> (2) show me a better way.
> 
> I have a problem that is very state-ful and I keep thinking of it as OO, 
> which is driving me crazy. Haskell is several times harder to use than 
> Python in this instance, probably because I'm doing it wrong.
> 

Stop the presses! I had an idea to make this more functional in style. Do 
it through multiple passes.

The idea is that we've got a list of musical events as input ("Node" is a 
term some algorithmic composers use, so I will use type Node.)

In fact we could have other types of input data too, so I might need the 
algebraic type

data InputType = Node ...
                | CSoundSource ...

etc.

Then we make a pass through the nodes using map concat to produce a bunch 
of Output data.

data Output = OIStatement ...
             | OInstrName InstrName  -- represents an instrument name
                                     -- (ultimately we need a number, but
                                     --  won't know that # during first
                                     --  pass)
             | OInstrNum Int         -- when we compute an instrument
                                     -- number, this will replace the above
             | OMixer MixerName
              ...

we have a function processInput:

processInput :: InputType -> [Output]

This expresses the idea that a single input may result in the generation of 
several pieces of output data.

The first pass is just a concat map

firstPass :: [InputType] -> [Output]
firstPass = concatMap processInput

In translating an InputType datum, we look at it "in isolation"---here it 
sits in front of us in the stream, and we haven't maintained a lot of 
state---and we translate it to some intermediate Output form, making all 
specific calculations or substitutions possible at that given time and context.

Then further passes are needed, many of which are folds. For example, to 
assign the instrument number I have some kind of NumberDatabase, but now my 
dealings with it are limited to a single fold.
assignNumbers :: [Output] -> NumberDatabase
assignNumbers outputList = foldl g newNumberDatabase outputList
   where g outputDatum numberDb =
            case outputDatum of
               OInstrName n -> ... ah! unassigned name! update db
               _            -> numberDb  -- just return unchanged


All the rest of the processing can be done via filters, folds, and maps.

Does this seem more functional in style?

Thanks,
Mike





More information about the Haskell-Cafe mailing list