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

Daniel Fischer daniel.is.fischer at web.de
Tue Dec 1 21:03:23 EST 2009


Am Mittwoch 02 Dezember 2009 02:01:29 schrieb Michael P Mossey:
> 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.

If you want to do something very stateful, it is a bit cumbersome in Haskell.
Perhaps it is the wrong approach and you can do it with much less state.
Or perhaps, this is possible, too, it is not a task for which Haskell is well suited.
Or perhaps you're really doing it wrong because of lack of experience.

>
> 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)

Yeah, that screams State Monad.

>
> 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?

If you're doing that in many places, factor out the methods

getOscillatorNumber :: String -> State MusicStuff Int
getOscillatorNumber str = do
    ms <- get
    let on = oscilatorNumbers ms
        (o1,newOn) = getNumber str on
    put (ms{ oscillatorNumbers = newOn })
    return o1

same for tableNumbers etc.

Then 

doSomeMusicStuff aString1 aString2 = do
    o <- getOscillatorNumber aString1
    t <- getTableNumber aString2
    return (o,t)

and the verbosity is moved to one place. That isn't worthwhile for seldomly used stuff, of 
course.

>
> Note that in Python it would be a method
>
> def doMusicStuff( self, s1, s2 ) :
>     return (self.oscillatorNumbers.next(s1),
> self.oscillatorNumbers.next(s2))
>

Yeah, mutability gives brevity here.



More information about the Haskell-Cafe mailing list