Tutorial for using the state monad or a better suggestion?

So the reason I keep pinging the list so much of late is I'm currently writing a GLUT program to visualize a heirarchical clustering of 18,000+ protein-protein interaction pairs (and associated gene-ontology terms). Thanks for the help on reading CSVs, those who wrote me back... my program intitializes and displays its first image within 6 seconds, about 10 times faster and in 10 times less memory than the Java program the guy was using. Now I'm to the point of making this thing interactive, and I I'm trying to figure out the Haskell way of doing this. Last time I wrote a program like this, I made a record data type with all the state and placed it into an IORef and curried it into the GLUT callback functions. I'm going to do the same thing now if there aren't cringes and wailings from people with a better sense of pure-functional aesthetics out there on the list with a willingness to either point me towards a tutorial that would help me do this better. Keep in mind that Graphics.UI.GLUT callbacks all want to return an IO (), and thus leftover state monads at ends of functions aren't going to be acceptable to the standard library... Any ideas? Oh, currently my program state includes: The geometry I'm rendering (Ptr GLfloat vertex and color arrays), The same geometry as a display list for rendering into the selection buffer An indexed and named tree that represents the clustering A tree of text containing tooltips to display The previous current mouse position (for dragging purposes) A couple of histograms as Array.IArray.Diff.DiffArrays Various parameters for constructing rendered data out of the indexed tree (for reconstruction after a node is collapsed/expanded) So I'm carrying around some pretty bulky state; should give you some understanding as to why I thougt the record data type would be the sanest way to do this without polluting my parameter list with individual IORrefs. Oh, and again, it's not that I don't know that I can make the IORef solution work, I can and I've done it before. It's just that I thought there might be a prettier way to do this. Thanks in advance! -- Jeff

I was trying to solve a similar problem while learning the FastCGI package. The regular CGI package allows the use of ReaderT to hold config data. Because FastCGI does the running of the passed in CGI action within a few calls to alloca :: (Ptr a -> IO b) -> IO b, I couldn't figure out a way to use monad transformers. I settled on the top-level IORef trick I've seen elsewhere:
bigBallOfState_ :: IORef MyState bigBallOfState_ = unsafePerformIO $ newIORef emptyState {-# NOINLINE bigBallOfState_ #-}
With a few accessors:
setState :: MyState -> IO () setState = ...
getState :: IO MyState getState = ...
I'm not going to pretend it's good style, and it assumes you only ever
need one copy of the state everywhere in your program.
-Antoine
On Fri, Feb 22, 2008 at 8:15 AM, Jefferson Heard
So the reason I keep pinging the list so much of late is I'm currently writing a GLUT program to visualize a heirarchical clustering of 18,000+ protein-protein interaction pairs (and associated gene-ontology terms). Thanks for the help on reading CSVs, those who wrote me back... my program intitializes and displays its first image within 6 seconds, about 10 times faster and in 10 times less memory than the Java program the guy was using.
Now I'm to the point of making this thing interactive, and I I'm trying to figure out the Haskell way of doing this. Last time I wrote a program like this, I made a record data type with all the state and placed it into an IORef and curried it into the GLUT callback functions. I'm going to do the same thing now if there aren't cringes and wailings from people with a better sense of pure-functional aesthetics out there on the list with a willingness to either point me towards a tutorial that would help me do this better. Keep in mind that Graphics.UI.GLUT callbacks all want to return an IO (), and thus leftover state monads at ends of functions aren't going to be acceptable to the standard library...
Any ideas? Oh, currently my program state includes:
The geometry I'm rendering (Ptr GLfloat vertex and color arrays), The same geometry as a display list for rendering into the selection buffer An indexed and named tree that represents the clustering A tree of text containing tooltips to display The previous current mouse position (for dragging purposes) A couple of histograms as Array.IArray.Diff.DiffArrays Various parameters for constructing rendered data out of the indexed tree (for reconstruction after a node is collapsed/expanded)
So I'm carrying around some pretty bulky state; should give you some understanding as to why I thougt the record data type would be the sanest way to do this without polluting my parameter list with individual IORrefs.
Oh, and again, it's not that I don't know that I can make the IORef solution work, I can and I've done it before. It's just that I thought there might be a prettier way to do this.
Thanks in advance!
-- Jeff _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Feb 22, 2008, at 9:15 , Jefferson Heard wrote:
Now I'm to the point of making this thing interactive, and I I'm trying to figure out the Haskell way of doing this. Last time I wrote a program like this, I made a record data type with all the state and placed it into an IORef and curried it into the GLUT callback functions. I'm going to do the same thing now if there aren't cringes and wailings from people with a better sense of pure-functional aesthetics out there on the list with a willingness to either point me towards a tutorial that would help me do this better. Keep in mind that Graphics.UI.GLUT callbacks all want to return an IO (), and thus leftover state monads at ends of functions aren't going to be acceptable to the standard library...
What I do (with gtk2hs) is visible at http://hpaste.org/3137 --- MWPState is a fairly large record. I will note that this code stores the mutable data in separate IORefs, whereas I'm told that it's better to use a single IORef with all the mutable state inside it. (For some reason I had assumed that the overhead would be higher.) That said, the wrappers make it fairly easy to refactor it. Since the IORef(s) and much of the remaining state is read-only, I use a ReaderT IO instead of StateT IO; this also turned out to be convenient for what turned out to be a significant optimization (in response to a timer firing, it collects a bunch of data and feeds it into a TreeView, and it turned out to be useful to collect it all at the front and use local to roll a modified record with the cached values). (The code in that paste is rather out of date, probably I should update it.) -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

Thanks. There seems to be some consensus developing around using
IORefs to hold all the program state.
-- Jeff
On Fri, Feb 22, 2008 at 12:11 PM, Brandon S. Allbery KF8NH
On Feb 22, 2008, at 9:15 , Jefferson Heard wrote:
Now I'm to the point of making this thing interactive, and I I'm trying to figure out the Haskell way of doing this. Last time I wrote a program like this, I made a record data type with all the state and placed it into an IORef and curried it into the GLUT callback functions. I'm going to do the same thing now if there aren't cringes and wailings from people with a better sense of pure-functional aesthetics out there on the list with a willingness to either point me towards a tutorial that would help me do this better. Keep in mind that Graphics.UI.GLUT callbacks all want to return an IO (), and thus leftover state monads at ends of functions aren't going to be acceptable to the standard library...
What I do (with gtk2hs) is visible at http://hpaste.org/3137 --- MWPState is a fairly large record.
I will note that this code stores the mutable data in separate IORefs, whereas I'm told that it's better to use a single IORef with all the mutable state inside it. (For some reason I had assumed that the overhead would be higher.) That said, the wrappers make it fairly easy to refactor it. Since the IORef(s) and much of the remaining state is read-only, I use a ReaderT IO instead of StateT IO; this also turned out to be convenient for what turned out to be a significant optimization (in response to a timer firing, it collects a bunch of data and feeds it into a TreeView, and it turned out to be useful to collect it all at the front and use local to roll a modified record with the cached values).
(The code in that paste is rather out of date, probably I should update it.)
-- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH
-- I try to take things like a crow; war and chaos don't always ruin a picnic, they just mean you have to be careful what you swallow. -- Jessica Edwards

jefferson.r.heard:
So the reason I keep pinging the list so much of late is I'm currently writing a GLUT program to visualize a heirarchical clustering of 18,000+ protein-protein interaction pairs (and associated gene-ontology terms). Thanks for the help on reading CSVs, those who wrote me back... my program intitializes and displays its first image within 6 seconds, about 10 times faster and in 10 times less memory than the Java program the guy was using.
Wonderful. I'm glad you're making progress. Be sure to lean on the friendly Haskell "consultants" of -cafe@ for help as you need it.
participants (4)
-
Antoine Latter
-
Brandon S. Allbery KF8NH
-
Don Stewart
-
Jefferson Heard