Compose
From HaskellWiki
(cont section, references, execWriter) |
(typo and a bit of extra detail) |
||
| Line 77: | Line 77: | ||
Our tactic here is really rather similar to that of the <hask>Reader</hask> example. We build up a computation which is the result of modifying the environment (or, actually, as we're working in <hask>Writer</hask>, we modify the output). <hask>censor</hask>, to quote All About Monad, "...takes a function and a <hask>Writer</hask> and produces a new <hask>Writer</hask> whose output is the same but whose log entry has been modified by the function.". So, we compose each function in turn onto the "log output" (which is actually a chain of composed functions). | Our tactic here is really rather similar to that of the <hask>Reader</hask> example. We build up a computation which is the result of modifying the environment (or, actually, as we're working in <hask>Writer</hask>, we modify the output). <hask>censor</hask>, to quote All About Monad, "...takes a function and a <hask>Writer</hask> and produces a new <hask>Writer</hask> whose output is the same but whose log entry has been modified by the function.". So, we compose each function in turn onto the "log output" (which is actually a chain of composed functions). | ||
| - | Once this computation has been | + | Once this computation has been built up, we extract this long composition chain, and apply it to our starting value. |
| + | |||
| + | Also interesting to note is that this method is really equivalent to the "Sane method" described above. We just iterate along the list, accumulating a composition chain. The only difference here is that we're using some of <hask>Writer</hask>'s plumbing to make it more subtle. | ||
== Using <hask>Cont</hask> == | == Using <hask>Cont</hask> == | ||
Revision as of 21:12, 14 May 2006
This page illustrates the solution in different monads. Most are a bit of a joke; you'd probably only ever use the first solution presented, but nevertheless the nice features of the various monads are demonstrated.
Contents |
1 The Sane Solution
compose :: [(a -> a)] -> a -> a compose fs v = foldl (flip (.)) id fs $ v
2 Using State
composeState :: [(a -> a)] -> a -> a composeState = execState . mapM modify
composeState fs v = execState (mapM modify fs) v
fs = mapM modify [(*2), (+1), \n -> (n - 5) * 4] -- fs is entirely equivalent to the following do-block: fs' = do modify (*2) modify (+1) modify (\n -> (n - 5) * 4)
In other words, we obtain a stateful computation that modifies the state with the first function in the list, then the second, and so on.
3 Using Reader
composeReader :: [(a -> a)] -> a -> a composeReader fs v = runReader (compose' fs) v where compose' [] = ask compose' (f:fs) = local f (compose' fs)
fs = compose' [(*2), (+1), \n -> (n - 5) * 4] -- again, this is entirely equivalent to the following: fs' = local (*2) $ local (+1) $ local (\n -> (n - 5) * 4) ask
Once this composition has been built up, we run it, starting off with an environment of the starting value.
4 Using Writer
composeWriter :: [(a -> a)] -> a -> a composeWriter fs v = (execWriter $ compose' fs) v where compose' [] = return id compose' (f:fs) = censor (. f) (compose' fs)
Once this computation has been built up, we extract this long composition chain, and apply it to our starting value.
Also interesting to note is that this method is really equivalent to the "Sane method" described above. We just iterate along the list, accumulating a composition chain. The only difference here is that we're using some of 5 Using Cont
I'm pretty sure this could be done, but I don't have a clue how! If you know 6 References
Mainly see All About Monads, specifically chapter two, which has overviews and examples for all the major monads.
7 The whole code
In case you wish to run this code, here it is in its entirety:
-- Thread a value through a list of function applications module Compose where import Control.Monad.Writer import Control.Monad.Reader import Control.Monad.State compose :: [(a -> a)] -> a -> a compose fs v = foldl (flip (.)) id fs $ v composeState :: [(a -> a)] -> a -> a composeState = execState . mapM modify composeReader :: [(a -> a)] -> a -> a composeReader fs v = runReader (compose' fs) v where compose' [] = ask compose' (f:fs) = local f (compose' fs) composeWriter :: [(a -> a)] -> a -> a composeWriter fs v = (execWriter $ compose' fs) v where compose' [] = return id compose' (f:fs) = censor (. f) (compose' fs) main = do let fs = [(+1), (*2), \n -> (n - 5) * 4] v = 3 putStrLn $ "compose: " ++ (show $ compose fs v) putStrLn $ "compostState: " ++ (show $ composeState fs v) putStrLn $ "composeReader: " ++ (show $ composeReader fs v) putStrLn $ "composeWriter: " ++ (show $ composeWriter fs v) {- *Compose> main compose: 12 compostState: 12 composeReader: 12 composeWriter: 12 -}
