From 6313833da8fbe53f777feb4343143c2d7503f661 Mon Sep 17 00:00:00 2001 From: simonm Date: Fri, 6 Feb 1998 10:37:53 +0000 Subject: [PATCH] [project @ 1998-02-06 10:37:53 by simonm] remove stray bit of documentation - it was getting in the way of 'make boot'. --- ghc/docs/simple-monad.lhs | 264 --------------------------------------------- 1 file changed, 264 deletions(-) delete mode 100644 ghc/docs/simple-monad.lhs diff --git a/ghc/docs/simple-monad.lhs b/ghc/docs/simple-monad.lhs deleted file mode 100644 index 3efb2b9..0000000 --- a/ghc/docs/simple-monad.lhs +++ /dev/null @@ -1,264 +0,0 @@ -A Simple Country Boy's Guide to Monadic-Style Programming -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Forget the category theory, forget all the fancy talk, forget "monadic -I/O", forget Phil Wadler's papers! Let's just do a little *plumbing* -in the monadic style, in plain-vanilla Haskell. - -You can compile this guide as a Haskell module; I haven't put in -enough code to make it run or do anytning interesting. Excuse me for -a moment, while I get some preliminaries out of the way... -\begin{code} -module Foo where - -infixr 9 `thenFoo`, `thenFoo_` -- ignore me - -data Foo = NullFoo | ConsFoo Int Foo -- assorted types, of little interest -type SwitchChecker = String -> Bool -type EnvA = [(String, Float)] -type NameSupply = Int -\end{code} - -*** MOTIVATION ********* - -If you find that your Haskell functions are starting to carry around a -lot of baggage ..., e.g., -\begin{code} -f :: EnvA -> SwitchChecker -> NameSupply -> Foo -> (Int, NameSupply) - -f env sw_chkr names NullFoo = (0, names) - -f env sw_chkr names (ConsFoo x xs) - = let - (x', names') = f env sw_chkr names xs - in - (x + x', names') -{- - `env' is some kind of environment; - what most people call "lookup tables". - `sw_chkr' is a function which, when presented with a - String, will tell you if that string was present - on the command line. - `names' is some kind of "name supply"; `f' - `f' returns a depleted name supply (2nd component of result). --} -\end{code} - -...then it may be time to use monadic code to hide some of the mess!! - -GRATUITOUS PLUMBING OF STATE MUST DIE. - - -*** SETTING UP THE MONAD MACHINERY ******* - -First, divide the things to be plumbed into: - - * things that are only passed "downwards" through the function; - in the example above, the `env' and `sw_chkr' are such things; - - * things that are "threaded" through the function; you want the - changed whatsit back from "down below"; `names' is such a thing. - -Now, implement your monad; let's call it `FooM'; think of a `FooM -Wibble' as an *action* that, when performed, produces a `Wibble'. - -\begin{code} -type FooM a = EnvA -- type of lookup-tbl being plumbed - -> SwitchChecker -- type of switch looker-upper... - -> NameSupply -- NameSupply going down... - -> (a, -- result of the `FooM a' action - NameSupply) -- NameSupply that comes back... -\end{code} - -(Note: in reality, it would be good practice to hide all this stuff -behind a clean interface, in another module.) - -Let's write the basic operations on these `FooM a' guys: - -\begin{code} -returnFoo :: a -> FooM a - -- make a `FooM thing' action from a `thing' value - -- [Phil W would call this `unitFoo'] - -thenFoo :: FooM a -> (a -> FooM b) -> FooM b - -- sequence two actions; the second uses the - -- result of the first - -- [Phil W would call this `bindFoo', or semi-colon :-] - -thenFoo_ :: FooM a -> FooM b -> FooM b - -- sequence two actions; don't care about the - -- result of the first - -- [the name is a mnemonic for "... thenFoo \ _ -> ...] -\end{code} - -They're implemented in the obvious way: -\begin{code} -returnFoo thing env sw_chkr ns = (thing, ns) - -thenFoo action1 action2 env sw_chkr ns - = case (action1 env sw_chkr ns) of - (result1, ns1) -> action2 result1 env sw_chkr ns1 - -thenFoo_ action1 action2 env sw_chkr ns - = case (action1 env sw_chkr ns) of - (_{-boring result-}, ns1) -> action2 env sw_chkr ns1 -\end{code} - -All those are "pure plumbing". We need a few "monadic functions" that -do something useful. - -For example, you need to be able to "do a `FooM' action" and get the -answer back (along with the depleted NameSupply); for that, use... -\begin{code} -initFoo :: FooM a -> SwitchChecker -> NameSupply -> (NameSupply, a) - -initFoo action sw_chkr ns - = case (action [] sw_chkr ns) of - (result, new_ns) -> (new_ns, result) - -- gratuitous order-swapping -\end{code} - -You would then have a this-monad-specific set of functions to ``reach -down'' in the plumbing and use the env, switch-checker, etc., that are -being carried around. Some examples might be: -\begin{code} -getNewName :: FooM Int - -getNewName env sw_chkr ns = (ns, ns+1) - ------------- - -ifSwitchSet :: String -> FooM a -> FooM a -> FooM a - -ifSwitchSet sw_to_chk then_ else_ env sw_chkr ns - = (if (sw_chkr sw_to_chk) then then_ else else_) env sw_chkr ns - ------------- - -lookupInEnv :: String -> FooM Float - -lookupInEnv key env sw_chkr ns - = case [ v | (k, v) <- env, k == key ] of - [] -> error "lookupInEnv: no match" - (val:_) -> (val, ns) -\end{code} - -*** USING THE MONAD MACHINERY ******* - -We now have everything needed to write beautiful (!) monadic code. To -remind you of the basic "monadic" functions at our disposal: - -\begin{verbatim} -returnFoo :: a -> FooM a -thenFoo :: FooM a -> (a -> FooM b) -> FooM b -thenFoo_ :: FooM a -> FooM b -> FooM b -initFoo :: FooM a -> SwitchChecker -> NameSupply -> (NameSupply, a) - -getNewName :: FooM Int -ifSwitchSet :: String -> FooM a -> FooM a -> FooM a -lookupInEnv :: String -> FooM Float -\end{verbatim} - -Before going on: there are a few plumbing things that aren't -essential, but tend to be useful. They needn't be written at the -"bare-bones" level; they show the use of `returnFoo' and `thenFoo'. -\begin{code} -mapFoo :: (a -> FooM b) -> [a] -> FooM [b] - -mapFoo f [] = returnFoo [] -mapFoo f (x:xs) - = f x `thenFoo` \ r -> - mapFoo f xs `thenFoo` \ rs -> - returnFoo (r:rs) - -mapAndUnzipFoo :: (a -> FooM (b,c)) -> [a] -> FooM ([b],[c]) - -mapAndUnzipFoo f [] = returnFoo ([],[]) -mapAndUnzipFoo f (x:xs) - = f x `thenFoo` \ (r1, r2) -> - mapAndUnzipFoo f xs `thenFoo` \ (rs1, rs2) -> - returnFoo (r1:rs1, r2:rs2) -\end{code} - -You should read - - f x `thenFoo` \ r -> ... - -as - - "do `f' with argument `x', giving result `r'". - -If you wanted, you could do really horrible things with the C -pre-processor (GHC and HBC let you do this...): -\begin{verbatim} -#define RETN returnFoo -#define BIND {--} -#define _TO_ `thenFoo` \ {--} - -mapFoo f [] = RETN [] -mapFoo f (x:xs) - = BIND (f x) _TO_ r -> - BIND (mapFoo f xs) _TO_ rs -> - RETN (r:rs) -\end{verbatim} - -*** USING THE MONAD MACHINERY, FOR REAL ******* - -We can finally re-write our `f' function in a "monadic style" (except -I'll call it `g'), using the functions above. -\begin{code} -g :: Foo -> FooM Int - -- `g' has the same arguments as `f' (really), but in a different - -- order: just unravel the type synonyms - -g NullFoo = returnFoo 0 - -g (ConsFoo x xs) - = g xs `thenFoo` \ x' -> - returnFoo (x + x') -\end{code} - -LOOK, MOM, NO GRATUITOUS PLUMBING OF STATE! - -OK, `g' shows how much the monadic style tidies up the plumbing, but -it is really boring---it doesn't use any of the functions we defined -earlier. Here's a function that does: -\begin{code} -h :: Int -> FooM Integer - -h x - = getNewName `thenFoo_` -- ignore that one... - getNewName `thenFoo` \ int_name -> - - mapAndUnzipFoo zwonk [int_name ..] - `thenFoo` \ (some_nums, more_nums) -> - - ifSwitchSet "-beat-hbc" ( - returnFoo (toInteger (some_nums !! 6) + 42) - - ) {-else-} ( - lookupInEnv "-ghc-is-cool" `thenFoo` \ ghc_float -> - returnFoo (toInteger (truncate ghc_float)) - ) - where - zwonk :: Int -> FooM (Int, Int) - zwonk i = returnFoo (i, x*i) -\end{code} - -*** CONCLUSION ******* - -Ordinary Haskell programming, but in a "monadic style", is a good way -to control the plumbing of state through your code. - -I have left out lots and lots of Neat Things you can do with monads -- -see the papers for more interesting stuff. But 99% of the monadic -code you're likely to write or see will look like the stuff in here. - -Comments, suggestions, etc., to me, please. - -Will Partain -partain@dcs.gla.ac.uk - -% compile with: -% ghc -cpp Foo.lhs -% hbc -M Foo.lhs -- 1.7.10.4