
On Tue, Mar 31, 2009 at 1:54 PM, Michael Mossey
I'm translating a Python program into Haskell, and running into a problem---a type of code where I don't know how to make the conceptual shift.
The Python code does a graphical layout of a music score. There is a loop in which it add items (chords, symbols, text, etc.) one at a time, moving to the right, until it reaches the end of the line. So in typical imperative code, we have a bunch of loop state, such as
- xpos of last chord or symbol placed - time of last chord or symbol placed - several StaffData objects, each containing the symbols that went on that particular staff - a cache of miscellaneous information about each symbol for later reference
So imperative code is pretty simple: loop, and each time update the state. Much of this state consists of lists to which symbols are added once per loop.
I'm not sure how to conceive of this problem in Haskell. Without using mutable variables, I would have to "rebuild" the state on each loop. I can do that, but I don't want to see an ugly proliferation of variables.
I would like to encapsulate the state in a single object so I can pass it around as a single variable, like
LoopState = LoopState { lastXPos :: Int, lastTime :: Double, staffDataLists :: [ ( String, StaffData ) ], chunkCache :: [ ( Double, Chunk ) ] }
So lets say I have an instance of this call x. Let's say I want to create y, by "updating" lastXPos. Do I have to do something like this:
newLastXPos = 25 y = LoopState ( newLastXPos, lastTime x, staffDataLists x, chunkCache x )
Obviously this is verbose compared to an imperative language in which one would say: newLastPos = 25 x.setLastXPos( newLastXPos )
I am aware that Haskell provides some mutable structures, but part of what drew me to Haskell was the benefit of avoiding mutable data (reducing bugs and making it easier to reason about my program's behavior). Are there any shortcuts for doing things like the above?
Have you considered the sort of named updates like the following? data Foo = Foo { i :: Int, j :: Int } deriving (Show) Loading that into ghci you can do things like this: *Foo> let f = Foo 25 25 *Foo> f Foo {i = 25, j = 25} *Foo> f { i = 35 } Foo {i = 35, j = 25} That might be more to your liking. /M -- Magnus Therning (OpenPGP: 0xAB4DFBA4) magnus@therning.org Jabber: magnus@therning.org http://therning.org/magnus identi.ca|twitter: magthe