[Haskell-cafe] seems like I'm on the wrong track
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
data InputType = Node ...
| CSoundSource ...
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
| 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?
More information about the Haskell-Cafe