On Tue, Dec 1, 2009 at 9:01 PM, Robert Greayer <[email protected]> wrote:
> > > On Tue, Dec 1, 2009 at 8:01 PM, Michael P Mossey > <[email protected]>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. >> >> To give you a larger context, this problem is essentially compiling a >> description of music (my own) into a kind of music-machine-language >> (CSound). CSound is relatively untidy. >> >> In this one example, in a OO way of thinking, I have data called >> AssignedNumbers that assigns integers to unique strings and keeps track of >> the used integers and next available integer (the choice of available >> integer could follow a number of conventions so I wanted to hide that in an >> ADT.) So it has an associated function: >> >> getNumber :: String -> AssignedNumbers -> (Int,AssignedNumbers) >> >> What getNumber does is: >> >> - check if the string already has a number assigned to it. If so, return >> that number. >> >> - if not, pick the next available number. >> >> - in all cases, return the possibly changed state of AssignedNumbers >> >> Then in a larger data structure, it contains fields of type >> AssignedNumbers. Like >> >> data MusicStuff = MusicStuff >> { oscillatorNumbers :: AssignedNumbers >> , tableNumbers :: AssignedNumbers >> , ... } >> >> I'm using MusicStuff in a State monad, so I might write a function like >> >> doSomeMusicStuff :: String -> String -> State MusicStuff (Int,Int) >> doSomeMusicStuff aString1 aString2 = do >> ms <- get >> (o1,newOscNums) = getNumber aString1 (oscillatorNumbers ms) >> (t1,newTabNums) = getNumber aString2 (tableNumbers ms) >> put ms { oscillatorNumbers = newOscNums >> , tableNumbers = newTabNums } >> return (o1,t1) >> >> For what it does, this is extremely verbose and filled with distracting >> visual content. And this is just a very simple example---my real problem is >> several times more state-ful. Is there a better way? >> > > As a quick observation, you might consider changing getNumber to be > something like: > > nextNumber :: String -> NumberGroup -> State MusicStuff Int > > where NumberGroup is something like > > data NumberGroup = OscNums | TabNums |... > > nextNumber updates the appropriate set of numbers in MusicStuff and returns > the number. doSomeMusicStuff then becomes: > > doSomeMusicStuff aString1 aString2 = (,) `liftM` nextNumber OscNums `ap` > nextNumber TabNums > > or better yet (applicatively) > > doSomeMusicStuff aString1 aString2 = (,) <$> nextNumber OscNums <*> > nextNumber TabNums > > Oops, that's: doSomeMusicStuff aString1 aString2 = (,) `liftM` nextNumber aString1 OscNums `ap` nextNumber aString2 TabNums or: doSomeMusicStuff aString1 aString2 = (,) <$> nextNumber aString1 OscNums <*> nextNumber aString2 TabNums
_______________________________________________ Haskell-Cafe mailing list [email protected] http://www.haskell.org/mailman/listinfo/haskell-cafe
