I've written and tested a collection of Haskell functions, and now I want to put them together into a "proper" program. The pattern of evaluation that I envisage is a program which maintains a workspace, and performs a sequence of read and write operations that reference and update this workspace, eventually returning some value based on the final state of the workspace. The workspace would seem to be appropriately manipulated using a form of state monad. And the I/O operations would be performed through an IO monad. What I'm unsure about is the best way to combine these so that the real-world state (IO) and workspace state are updated (threaded?) in parallel. I think I can imagine a solution that defines a new monad consisting of an IO paired with a state monad, and then implementing the monadic operators and access functions to manage the combined I/O and state updates. I haven't thought through the details, but my intuition is that it might be a fair amount of additional code. I notice the XML toolbox implements a similar idea [1], though in that case the state is not a separate monad, just combined with IO in a new monad type. [1] http://www.fh-wedel.de/~si/HXmlToolbox/hdoc/MonadStateIO.html I imagine that this is a common requirement, for which there exists an appropriately packaged solution. Is there a standard solution I should look to for this kind of functionality? Or is there some completely different approach that I've overlooked? #g ------------------- Graham Klyne <GK@NineByNine.org> PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E
On Thu, May 15, 2003 at 12:14:31PM +0100, Graham Klyne wrote:
I've written and tested a collection of Haskell functions, and now I want to put them together into a "proper" program.
The pattern of evaluation that I envisage is a program which maintains a workspace, and performs a sequence of read and write operations that reference and update this workspace, eventually returning some value based on the final state of the workspace.
The workspace would seem to be appropriately manipulated using a form of state monad. And the I/O operations would be performed through an IO monad. What I'm unsure about is the best way to combine these so that the real-world state (IO) and workspace state are updated (threaded?) in parallel.
[...]
I imagine that this is a common requirement, for which there exists an appropriately packaged solution. Is there a standard solution I should look to for this kind of functionality? Or is there some completely different approach that I've overlooked?
You probably want Monad Transformers. Both GHC and Hugs provide a library of monad transformers for adding state, continuations, exceptions, etc. They can be smoothly use with IO monad. Here is an example of using state monad transformer. import Control.Monad import Control.Monad.Trans import Control.Monad.State import IO (try) main :: IO () main = runStateT m 0 >> return () where m = do r <- liftIO (try getLine) either (const $ return ()) (\l -> do n <- next liftIO (putStrLn (show n ++ ": " ++ l)) m) r next = do x <- fmap succ get put x return x Googling for Monad Transformers should give you much info on this topic. Regards, Tom -- .signature: Too many levels of symbolic links
On 15 May, Tomasz Zielonka wrote:
On Thu, May 15, 2003 at 12:14:31PM +0100, Graham Klyne wrote:
[..]
The workspace would seem to be appropriately manipulated using a form of state monad. And the I/O operations would be performed through an IO monad. What I'm unsure about is the best way to combine these so that the real-world state (IO) and workspace state are updated (threaded?) in parallel.
[...]
You probably want Monad Transformers. Both GHC and Hugs provide a library of monad transformers for adding state, continuations, exceptions, etc. They can be smoothly use with IO monad. Here is an example of using state monad transformer. [...]
I find this works well too. I typically put these in another module and create type synonyms for them (and sometimes state getters/setters). This allows one to easily change the type in the state without rewriting all the functions that use your type. Similarly, it becomes easy to change the Monad as well. For instance, you may start with State combined with IO and then find you need to also combine exception in later. As an example of how I set up the types, the following is a short excerpt from code for a stack machine Assembler that I wrote. (AssState etc are other types declared elsewhere. The Monad transformer types typically follow the pattern of ending in "T" and taking a Monad as one of their subordinate types.
import MonadState import MonadError
type Assem = ErrorT [Char] (StateT AssState IO ) type AssemOp = ErrorT [Char] (StateT String IO )
type IOMachine = ErrorT [Char] (StateT (Machine,ProgramState) IO )
and some of the getters/setters are:
getMach::IOMachine Machine getMach = do (m,_ ) <-get return m
putMach::Machine->IOMachine() putMach m = do (_,ps)<- get put (m,ps)
putStrIOM::String->IOMachine() putStrIOM = lift.lift.putStr putStrLnIOM::String->IOMachine() putStrLnIOM = lift.lift.putStrLn
getStack::IOMachine (MStack StackPtr StackVal) getStack = do mach <-getMach return $ stack mach -- Brett G. Giles Grad Student, University of Calgary Formal Methods, Category Theory, Semantics of Programming http://www.cpsc.ucalgary.ca/~gilesb mailto:gilesb@cpsc.ucalgary.ca
At 15:31 15/05/03 +0200, Tomasz Zielonka wrote:
You probably want Monad Transformers. [...]
"Just when you thought it was safe to get back in the water...." Or, in my case, just when I thought I was beginning to understand how to use FP... This response was very helpful, thank you, even if it has served to show me there's still very much more I need to learn. I've just read through Mark Jones' paper [1], and can't claim to fully understand it but I do begin to see the way forward. It appears that what I want in the near term is to apply "StateT" to "IO". Hopefully, working with that will help to develop my intuitions for the more general cases. (It would help if the GHC libraries were more documented, but I guess we can't expect everything on a plate just yet.) #g -- [1] Functional Programming with Overloading and Higher-Order Polymorphism, Mark P Jones, Advanced School of Functional Programming, 1995. http://www.cse.ogi.edu/~mpj/pubs/springschool.html At 15:31 15/05/03 +0200, Tomasz Zielonka wrote:
On Thu, May 15, 2003 at 12:14:31PM +0100, Graham Klyne wrote:
I've written and tested a collection of Haskell functions, and now I want to put them together into a "proper" program.
The pattern of evaluation that I envisage is a program which maintains a workspace, and performs a sequence of read and write operations that reference and update this workspace, eventually returning some value based on the final state of the workspace.
The workspace would seem to be appropriately manipulated using a form of state monad. And the I/O operations would be performed through an IO monad. What I'm unsure about is the best way to combine these so that the real-world state (IO) and workspace state are updated (threaded?) in parallel.
[...]
I imagine that this is a common requirement, for which there exists an appropriately packaged solution. Is there a standard solution I should look to for this kind of functionality? Or is there some completely different approach that I've overlooked?
You probably want Monad Transformers. Both GHC and Hugs provide a library of monad transformers for adding state, continuations, exceptions, etc. They can be smoothly use with IO monad. Here is an example of using state monad transformer.
import Control.Monad import Control.Monad.Trans import Control.Monad.State import IO (try)
main :: IO () main = runStateT m 0 >> return () where m = do r <- liftIO (try getLine) either (const $ return ()) (\l -> do n <- next liftIO (putStrLn (show n ++ ": " ++ l)) m) r
next = do x <- fmap succ get put x return x
Googling for Monad Transformers should give you much info on this topic.
Regards, Tom
-- .signature: Too many levels of symbolic links _______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
------------------- Graham Klyne <GK@NineByNine.org> PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E
On Thu, 15 May 2003 21:07:47 +0100 Graham Klyne <GK@ninebynine.org> wrote:
It appears that what I want in the near term is to apply "StateT" to "IO". Hopefully, working with that will help to develop my intuitions for the more general cases. (It would help if the GHC libraries were more documented, but I guess we can't expect everything on a plate just yet.)
See MonadTemplateLibrary on HaWiki, there is documentation of many of the Monad* classes. While the transformers aren't explicitly documented, they are all instances of their respective Monad* class. About the only thing you need to know about besides that for monad transformers is lift, liftIO, and how certain features interact when lifted through certain monads (like callCC through State).
On Sat, 17 May 2003, Derek Elkins wrote:
On Thu, 15 May 2003 21:07:47 +0100 Graham Klyne <GK@ninebynine.org> wrote:
It appears that what I want in the near term is to apply "StateT" to "IO". Hopefully, working with that will help to develop my intuitions for the more general cases. (It would help if the GHC libraries were more documented, but I guess we can't expect everything on a plate just yet.)
See MonadTemplateLibrary on HaWiki, there is documentation of many of the Monad* classes. While the transformers aren't explicitly documented, they are all instances of their respective Monad* class. (snip)
Yes, and mixing StateT with IO has an explicit example at the end of 1.4 at http://haskell.org/hawiki/MonadState -- Mark
This may be a very dumb question, but... I've been digging around Monad transformers, trying to get the feel of how to use them. In part, I'm referring to the library source code, and come across the following in Control.Monad.State, which I'm having trouble figuring out: [[ -- MonadState class -- -- get: returns the state from the internals of the monad. -- put: changes (replaces) the state inside the monad. class (Monad m) => MonadState s m | m -> s where get :: m s put :: s -> m () ]] What does the vertical bar "|" in the class declaration mean? I can't find this use mentioned in the Haskell report or the GHC type system extensions. #g ------------------- Graham Klyne <GK@NineByNine.org> PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E
Graham Klyne wrote:
This may be a very dumb question, but...
I've been digging around Monad transformers, trying to get the feel of how to use them. In part, I'm referring to the library source code, and come across the following in Control.Monad.State, which I'm having trouble figuring out:
[[ -- MonadState class -- -- get: returns the state from the internals of the monad. -- put: changes (replaces) the state inside the monad.
class (Monad m) => MonadState s m | m -> s where get :: m s put :: s -> m () ]]
What does the vertical bar "|" in the class declaration mean? I can't find this use mentioned in the Haskell report or the GHC type system extensions.
#g
See: http://www.haskell.org/ghc/docs/latest/html/users_guide/type-extensions.html... Dean
On Fri, 16 May 2003 14:51:19 +0100, Graham Klyne <GK@ninebynine.org> wrote:
What does the vertical bar "|" in the class declaration mean? I can't find this use mentioned in the Haskell report or the GHC type system extensions.
As someone else has already noted, this is a functional dependency. I'd just like to note that if you want to stay within Haskell 98, it's still perfectly possible to define the state monad transformer - all you lose is the MonadState class. Also, I strongly recommend the use of a record to keep your state - if you use a tuple, then each time you add something new you'll have to change all the getters and setters (or any other code that acts directly on the structure of the state). Cheers, Ganesh
G'day all. On Sat, May 17, 2003 at 12:30:11PM +0100, Ganesh Sittampalam wrote:
Also, I strongly recommend the use of a record to keep your state - if you use a tuple, then each time you add something new you'll have to change all the getters and setters (or any other code that acts directly on the structure of the state).
One thing that I've also found useful is to stack a ReaderT on top of IO, and store a record of IORefs in the ReaderT state. This way, not only is it extensible, but you don't pay the cost of repacking the state tuple in code that modifies state a lot. You could, of course, also do this with STRefs. Cheers, Andrew Bromage
On Fri, 16 May 2003 14:51:19 +0100 Graham Klyne <GK@ninebynine.org> wrote:
This may be a very dumb question, but...
I've been digging around Monad transformers, trying to get the feel of how to use them. In part, I'm referring to the library source code, and come across the following in Control.Monad.State, which I'm having trouble figuring out:
[[ -- MonadState class -- -- get: returns the state from the internals of the monad. -- put: changes (replaces) the state inside the monad.
class (Monad m) => MonadState s m | m -> s where get :: m s put :: s -> m () ]]
What does the vertical bar "|" in the class declaration mean? I can't find this use mentioned in the Haskell report or the GHC type system extensions.
It's mentioned in GHC's type extensions, but only as a reference to a paper. The '| m -> s' is a functional dependency. You could certainly use MonadState without even knowing about it, all you really need to know is what get and put do and that's fairly straightforward.
At 17:54 18/05/03 -0400, Derek Elkins wrote:
What does the vertical bar "|" in the class declaration mean? I can't find this use mentioned in the Haskell report or the GHC type system extensions.
It's mentioned in GHC's type extensions, but only as a reference to a paper. The '| m -> s' is a functional dependency.
OK, got it, thanks to everyone for help and suggestions. Here are a couple of small notes/suggestions for the community's consideration (pending more complete documentation): (1) It may help if the brief section in the GHC libraries pages hinted at the syntax. That would have helped me to identify the usage. e.g. add something like this to http://www.haskell.org/ghc/docs/latest/html/users_guide/type-extensions.html... [[ Functional dependencies are introduced by a vertical bar in the syntax of a class declaration; e.g. "class (Monad m) => MonadState s m | m -> s where ...". ]] (2) I note that the wiki page at http://haskell.org/hawiki/FunDeps mentions Mark Jones paper thus "See the paper[1] by Mark P. Jones", but I see no actual reference for the citation [1]. I guess it's the same as that referenced by the GHC user guide, i.e. http://www.cse.ogi.edu/~mpj/pubs/fundeps.html ? #g ------------------- Graham Klyne <GK@NineByNine.org> PGP: 0FAA 69FF C083 000B A2E9 A131 01B9 1C7A DBCA CB5E
On Mon, 19 May 2003 11:45:47 +0100 Graham Klyne <gk@ninebynine.org> wrote:
At 17:54 18/05/03 -0400, Derek Elkins wrote:
What does the vertical bar "|" in the class declaration mean? I can't find this use mentioned in the Haskell report or the GHC type system extensions.
It's mentioned in GHC's type extensions, but only as a reference to a paper. The '| m -> s' is a functional dependency.
OK, got it, thanks to everyone for help and suggestions.
Here are a couple of small notes/suggestions for the community's consideration (pending more complete documentation):
(1) It may help if the brief section in the GHC libraries pages hinted at the syntax. That would have helped me to identify the usage. e.g. add something like this to http://www.haskell.org/ghc/docs/latest/html/users_guide/type-extensions.html... [[ Functional dependencies are introduced by a vertical bar in the syntax of a class declaration; e.g. "class (Monad m) => MonadState s m | m -> s where ...". ]]
I'd like documentation on the syntax at all as implemented. I don't remember the paper being to clear about more involved cases.
(2) I note that the wiki page at http://haskell.org/hawiki/FunDeps mentions Mark Jones paper thus "See the paper[1] by Mark P. Jones", but I see no actual reference for the citation [1]. I guess it's the same as that referenced by the GHC user guide, i.e. http://www.cse.ogi.edu/~mpj/pubs/fundeps.html ?
Old style links like that were lost when the Haskell Wiki was updated, just fix things like that as you come across them.
G'day all. On Mon, May 19, 2003 at 11:45:47AM +0100, Graham Klyne wrote:
I note that the wiki page at http://haskell.org/hawiki/FunDeps mentions Mark Jones paper thus "See the paper[1] by Mark P. Jones", but I see no actual reference for the citation [1].
As Derek mentioned, it's bit rot from the old wiki. I fixed it. Cheers, Andrew Bromage
participants (9)
-
Andrew J Bromage -
Dean Herington -
Derek Elkins -
Ganesh Sittampalam -
gilesb@cpsc.ucalgary.ca -
Graham Klyne -
Graham Klyne -
Mark Carroll -
Tomasz Zielonka