# User:Benmachine/Cont

### From HaskellWiki

Benmachine (Talk | contribs) |
Benmachine (Talk | contribs) |
||

(28 intermediate revisions by one user not shown) | |||

Line 1: | Line 1: | ||

− | + | == A practical Cont tutorial == | |

− | + | It seems to me like <hask>Cont</hask> and <hask>ContT</hask> is way simpler than people make it. I think it's just a way to give a name to the "tail" of a do-block. | |

+ | |||

+ | '''Warning:''' I'm going to use some metaphors here, like the <tt>Magic</tt> type, that probably shouldn't be interpreted perfectly literally. Try to understand the gist, rather than worrying about the details. | ||

<haskell> | <haskell> | ||

− | + | contstuff :: Magic | |

− | + | contstuff = do | |

+ | thing1 | ||

+ | thing2 | ||

+ | -- Now I want to manipulate the rest of the computation. | ||

+ | -- So I want a magic function that will give me the future to | ||

+ | -- play with. | ||

+ | magic $ \rest -> | ||

+ | -- 'rest' is the rest of the computation. Now I can just do it, | ||

+ | -- or do it twice and combine the results, or discard it entirely, | ||

+ | -- or do it and then use the result to do it again... it's easy to | ||

+ | -- imagine why this might be useful. | ||

+ | messAboutWith rest | ||

− | + | thing3 -- these might get done once, several times, | |

− | + | thing4 -- or not at all. | |

</haskell> | </haskell> | ||

− | + | The question is, what type should <hask>magic</hask> have? Well, let's say the whole do-block results in a thing of type <hask>r</hask> (without thinking too hard about what this means). Then certainly the function we give <hask>magic</hask> should result in type <hask>r</hask> as well, since it can run that do-block. The function should also accept a single parameter, referring to the tail of the computation. That's the rest of the do-block, which has type <hask>r</hask>, right? Well, more or less, with one caveat: we might bind the result of <hask>magic</hask>: | |

− | + | <haskell> | |

+ | x <- magic $ \rest -> -- ... | ||

+ | thingInvolving x | ||

+ | </haskell> | ||

− | + | so the rest of the do-block has an <hask>x</hask> in it that we need to supply (as well as other variables, but <hask>magic</hask> already has access to those). So the rest of the do-block can be thought of as a bit like <hask>a -> r</hask>. Given access to the rest of that do-block, we need to produce something of type <hask>r</hask>. So our lambda has type <hask>(a -> r) -> r</hask> and hence <hask>magic :: (a -> r) -> r -> Magic</hask>... oh but ''this'' looks familiar... | |

<haskell> | <haskell> | ||

− | + | newtype Cont r a = Cont { runCont :: (a -> r) -> r } | |

− | + | -- Magic = Cont r a | |

+ | |||

+ | magic = Cont | ||

+ | </haskell> | ||

+ | Tada! The moral of the story is, if you got up one morning and said to yourself "I want to stop in the middle of a do-block and play about with the last half of it", then <tt>Cont</tt> is the type you would have come up with. | ||

+ | |||

+ | ---- | ||

+ | |||

+ | Now you know what the <tt>Cont</tt> type is, you can implement pretty much all of its type class instances just from there, since the types force you to apply this to that and compose that with this. But that doesn't really help you to understand what's going on: here's a way of using the intuition introduced above to implement `Functor` without thinking about the types too much: | ||

+ | |||

+ | <haskell> | ||

+ | instance Functor (Cont r) where | ||

+ | fmap f (Cont x) = -- ... | ||

+ | </haskell> | ||

+ | Well, we've got to build a <hask>Cont</hask> value, and those always start the same way: | ||

+ | <haskell> | ||

+ | fmap f (Cont x) = Cont $ \rest -> -- ... | ||

+ | </haskell> | ||

+ | Now what? Well, remember what <hask>x</hask> is. It comes from inside a <hask>Cont</hask>, so it looks like <hask>\rest -> stuffWith (rest val)</hask>, where <hask>val</hask> is the 'value' of the computation (what would be bound with <hask><-</hask>). So we want to give it a <hask>rest</hask>, but we don't want it to be called with the 'value' of the computation - we want <hask>f</hask> to be applied to it first. Well, that's easy: | ||

+ | <haskell> | ||

+ | fmap f (Cont x) = Cont $ \rest -> x (\val -> rest (f val)) | ||

+ | </haskell> | ||

+ | |||

+ | Load it in `ghci` and the types check. Amazing! Emboldened, let's try <hask>Applicative</hask> | ||

+ | |||

+ | <haskell> | ||

+ | instance Applicative (Cont r) where | ||

+ | pure x = Cont $ \rest -> -- ... | ||

+ | </haskell> | ||

+ | |||

+ | We don't want to do anything special here. The rest of the computation wants a value, let's just give it one: | ||

+ | |||

+ | <haskell> | ||

+ | pure x = Cont $ \rest -> rest x | ||

+ | </haskell> | ||

+ | |||

+ | What about <hask><*></hask>? | ||

+ | |||

+ | <haskell> | ||

+ | Cont f <*> Cont x = Cont $ \rest -> -- ... | ||

+ | </haskell> | ||

+ | |||

+ | This is a little trickier, but if we look at how we did <hask>fmap</hask> we can guess at how we get the function and the value out to apply one to the other: | ||

+ | |||

+ | <haskell> | ||

+ | Cont f <*> Cont x = Cont $ \rest -> f (\fn -> x (\val -> rest (fn val))) | ||

+ | </haskell> | ||

+ | |||

+ | <hask>Monad</hask> is a harder challenge, but the same basic tactic applies. Hint: remember to unwrap the newtype with <hask>runCont</hask>, <hask>case</hask>, or <hask>let</hask> when necessary. | ||

+ | |||

+ | === So what's callCC? === | ||

+ | |||

+ | "Call with current continuation". Basically, you use <hask>callCC</hask> like this: | ||

+ | |||

+ | <haskell> | ||

+ | ret <- callCC $ \exit -> do | ||

+ | -- A mini Cont block. | ||

+ | -- You can bind things to ret in one of two ways: either return | ||

+ | -- something at the end as usual, or call exit with something of | ||

+ | -- the appropriate type, and the rest of the block will be ignored. | ||

+ | when (n < 10) $ exit "small!" | ||

+ | when (n > 100) $ exit "big!" | ||

+ | return "somewhere in between!" | ||

+ | </haskell> | ||

+ | |||

+ | See if you can work out the type (not too hard: work out the type of exit first, then the do block) then the implementation. Try not to follow the types ''too'' much: they will tell you ''what'' to write, but not ''why''. Think instead about the strategies we used above, and what each bit ''means''. Hints: remember that <hask>exit</hask> throws stuff away, and remember to use <hask>runCont</hask> or similar, as before. | ||

+ | |||

+ | === What about ContT? === | ||

+ | |||

+ | The thing to understand with <hask>ContT</hask> is that it's exactly the same trick. Literally. To the point where I ''think'' the following definition works fine: | ||

+ | |||

+ | <haskell> | ||

+ | newtype ContT r m a = ContT (Cont (m r) a) | ||

+ | deriving (Functor, Applicative, Monad) | ||

+ | |||

+ | runContT :: ContT r m a -> (a -> m r) -> m r | ||

+ | runContT (ContT m) = runCont m | ||

+ | </haskell> | ||

+ | |||

+ | The only reason the newtype exists at all is to shuffle the type parameters around a bit, so that instances of things like <hask>MonadTrans</hask> can be defined. | ||

+ | |||

+ | === Some real examples === | ||

+ | |||

+ | I find he examples in the mtl doc unconvincing. They don't do anything genuinely daring, and some of them don't use the features of <tt>Cont</tt> at all – they work in any monad! Here's a more complex example: | ||

+ | |||

+ | <haskell> | ||

+ | -- This tends to be useful. | ||

+ | runC :: Cont a a -> a | ||

+ | runC c = runCont c id | ||

+ | |||

+ | faff :: Integer -> Maybe Integer | ||

+ | faff n = runC $ do | ||

+ | test <- Cont $ \try -> case try n of | ||

+ | Nothing -> try (2*n) | ||

+ | res -> fmap (subtract 10) res | ||

+ | return $ if test < 10 then Nothing else Just test | ||

+ | </haskell> | ||

+ | |||

+ | In <hask>faff</hask>, the <hask>return</hask> statement is run with <hask>test = n</hask>: if it succeeds then we subtract 10 from the result and return it. If it fails we try again, but with <hask>(2*n)</hask>: note that if this succeeds, we don't subtract 10. | ||

+ | |||

+ | As an exercise, see if you can work out, without using <tt>ghci</tt>, how to make the function return: (a) <tt>Nothing</tt>, (b) <tt>Just 12</tt>, (c) <tt>Just 0</tt>. | ||

+ | |||

+ | === Acknowledgements === | ||

+ | |||

+ | I think it was [http://blog.sigfpe.com/ the legendary sigfpe] who made this click for me, after thinking about how this works: | ||

+ | * [http://blog.sigfpe.com/2011/10/quick-and-dirty-reinversion-of-control.html Quick and dirty reinversion of control] | ||

+ | and there's also this: | ||

+ | * [http://blog.sigfpe.com/2008/12/mother-of-all-monads.html The Mother of all Monads] | ||

+ | which is more-or-less the above trick but in a bit more detail. | ||

+ | |||

+ | === Disclaimer === | ||

+ | |||

+ | I'm currently unsure if I've fallen victim to Brent's (in)famous [http://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/ monad tutorial fallacy]. I know that there was more in my learning process than I've been able to reproduce above, but I do think I'm doing this in a genuinely new style – <hask>Cont</hask> always seems to be presented in such vague terms, and people don't provide actual examples of the way it works. | ||

+ | |||

+ | === A moderately heretical conclusion === | ||

+ | |||

+ | Sometimes looking at types isn't the best way to understand things! I've implemented the <hask>Cont</hask> type class instances before, and the types ensure that you pretty much can't help but do it the right way. But that doesn't tell you what you're doing, or why you did it that way. I never understood <hask>Cont</hask> until I came across the natural interpretation of its content. It's a bit like fitting the pieces of a puzzle together without looking at the picture. |

## Latest revision as of 21:34, 20 January 2012

## Contents |

## [edit] 1 A practical Cont tutorial

It seems to me like**Warning:** I'm going to use some metaphors here, like the `Magic` type, that probably shouldn't be interpreted perfectly literally. Try to understand the gist, rather than worrying about the details.

contstuff :: Magic contstuff = do thing1 thing2 -- Now I want to manipulate the rest of the computation. -- So I want a magic function that will give me the future to -- play with. magic $ \rest -> -- 'rest' is the rest of the computation. Now I can just do it, -- or do it twice and combine the results, or discard it entirely, -- or do it and then use the result to do it again... it's easy to -- imagine why this might be useful. messAboutWith rest thing3 -- these might get done once, several times, thing4 -- or not at all.

x <- magic $ \rest -> -- ... thingInvolving x

*this*looks familiar...

newtype Cont r a = Cont { runCont :: (a -> r) -> r } -- Magic = Cont r a magic = Cont

Tada! The moral of the story is, if you got up one morning and said to yourself "I want to stop in the middle of a do-block and play about with the last half of it", then `Cont` is the type you would have come up with.

Now you know what the `Cont` type is, you can implement pretty much all of its type class instances just from there, since the types force you to apply this to that and compose that with this. But that doesn't really help you to understand what's going on: here's a way of using the intuition introduced above to implement `Functor` without thinking about the types too much:

instance Functor (Cont r) where fmap f (Cont x) = -- ...

fmap f (Cont x) = Cont $ \rest -> -- ...

fmap f (Cont x) = Cont $ \rest -> x (\val -> rest (f val))

instance Applicative (Cont r) where pure x = Cont $ \rest -> -- ...

We don't want to do anything special here. The rest of the computation wants a value, let's just give it one:

pure x = Cont $ \rest -> rest x

Cont f <*> Cont x = Cont $ \rest -> -- ...

Cont f <*> Cont x = Cont $ \rest -> f (\fn -> x (\val -> rest (fn val)))

### [edit] 1.1 So what's callCC?

"Call with current continuation". Basically, you useret <- callCC $ \exit -> do -- A mini Cont block. -- You can bind things to ret in one of two ways: either return -- something at the end as usual, or call exit with something of -- the appropriate type, and the rest of the block will be ignored. when (n < 10) $ exit "small!" when (n > 100) $ exit "big!" return "somewhere in between!"

*too*much: they will tell you

*what*to write, but not

*why*. Think instead about the strategies we used above, and what each bit

*means*. Hints: remember that

### [edit] 1.2 What about ContT?

The thing to understand with*think*the following definition works fine:

newtype ContT r m a = ContT (Cont (m r) a) deriving (Functor, Applicative, Monad) runContT :: ContT r m a -> (a -> m r) -> m r runContT (ContT m) = runCont m

### [edit] 1.3 Some real examples

I find he examples in the mtl doc unconvincing. They don't do anything genuinely daring, and some of them don't use the features of `Cont` at all – they work in any monad! Here's a more complex example:

-- This tends to be useful. runC :: Cont a a -> a runC c = runCont c id faff :: Integer -> Maybe Integer faff n = runC $ do test <- Cont $ \try -> case try n of Nothing -> try (2*n) res -> fmap (subtract 10) res return $ if test < 10 then Nothing else Just test

As an exercise, see if you can work out, without using `ghci`, how to make the function return: (a) `Nothing`, (b) `Just 12`, (c) `Just 0`.

### [edit] 1.4 Acknowledgements

I think it was the legendary sigfpe who made this click for me, after thinking about how this works:

and there's also this:

which is more-or-less the above trick but in a bit more detail.