For working with record fields inside of state monads I would recommend trying out one of these packages: lenses fclabels data-accessor (I think I'm forgetting a couple)
They all have special mechanisms for working with record fields inside state monads (and have lots of other cool stuff) I'm partial to lenses (I wrote it :) ), but the others are quite good as well. Hmmm I just noticed that hackage is not generating the documentation for latest version of lenses. I shall have to find out why. In the meantime, the documentation for the 0.1.2 version is essentially the same. - Job On Thu, Jul 8, 2010 at 4:08 AM, Michael Mossey <m...@alumni.caltech.edu>wrote: > I'm fairly beginnerish to Haskell, and come from OO. I have a complaint > about Haskell, but I think I found a good solution. Any suggestions welcome. > > I have RSI and like to minimize typing. The use of classes as name spaces > helps to do that. Also I can use some Emacs abbreviation magic easily with > OO and not so easily with Haskell. I'll explain in a second. > > In Haskell, when defining data for complex programs I like to use named > fields to allow for changing data definitions without having to change all > code. But named fields are top-level functions (I think). They must be > chosen not to clash. > > My habit has been to prefix them with the name of the constructor. So in a > program for playing back musical documents that needs to track some state, > we have: > > data PlayState = PlayState > { playState_cursor :: Int > , playState_verts :: [Loc] > , playState_len :: Int > , playState_doc :: MusDoc > } > > Note all these "playState_" prefixes. Lots of typing, which is not good. > > In OO, you could type > > x.cursor() > > In Haskell you have to type > > playState_cursor x > > which also, I feel, is harder to read. > > Now suppose I want to use PlayState with a State monad. > > -- Increment the cursor. > incrCursor :: State PlayState () > incrCursor = > cur <- gets playState_cursor > len <- gets playState_len > let newCur = min (cur+1) (len-1) > p <- get > put $ p {playState_cursor = newCur} > > Okay, I'm sorry, that is just a lot of typing for what it is doing. Not > good for people with RSI, and not all that readable. > > I could define a function to make modifying the state a little easier. > > playState_update_cursor :: Int -> PlayState -> PlayState > playState_update_cursor i p = p {playState_cur=i} > > Then incrCursor would look like: > > incrCursor :: State PlayState () > incrCursor = > cur <- gets playState_cursor > len <- gets playState_len > let newCur = min (cur+1) (len-1) > modify (playState_update_cursor newCur) > > Notice how often the characters "playState_" get typed. This would be a > great situation for Emacs abbreviations. When you define an abbreviation in > Emacs, such as defining "xps" to expand to "PlayState", emacs will watch for > the characters xps. It will then replace "xps" with "PlayState" when you > type a non-alphanumeric character following "xps". So if I type "xps." the > moment I hit "." it changes to "PlayState." > > But I would have a hard time using this feature with "playState_" because > it is always followed by an alphanumeric character. > > So my idea, now, is to put the definition of PlayState in its own module > and import it qualified as PlayState. > > ---------------- module PlayState -------------- > > data PlayState = PlayState > { cursor :: Int > , verts :: [Loc] > , len :: [Int] > , doc :: MusDoc > } > > update_cursor i p = p {cursor = i} > > ----------------------------------------------- > > I got rid of the "playState_" prefixes because I am not worried about using > generic field names like "doc". They won't clash if I always import this > qualified. And that reduces the necessary typing in the definition. > > Now my monad looks like > > testMonad = do > cursor <- gets PlayState.cursor > len <- gets PlayState.len > let newCur = min (cur+1) (len-1) > modify $ PlayState.update_cursor newCur > > Now I can define an abbreviation for PlayState. This is a big help. Also, I > find this more readable. To me > > PlayState.cursor > > is more readable than > playState_cursor > > For one thing, syntax highlighting helps in the former case. For another, > the latter case requires that you recognize a naming convention, but the > former case says clearly: "cursor is within the namespace PlayState, so this > combination must be describing a cursor related to PlayState." > > > > > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe >
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe