# User:Benmachine/Cont

### From HaskellWiki

< User:Benmachine(Difference between revisions)

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

Line 1: | Line 1: | ||

I found a [[User:benmachine/hasktag_bug|bug with the <hask> tag]]. I put it on its own page so it doesn't ruin my user page. | I found a [[User:benmachine/hasktag_bug|bug with the <hask> tag]]. I put it on its own page so it doesn't ruin my user page. | ||

− | It seems to me like <hask>Cont</hask> and <hask>ContT</hask> is way simpler than people make it. Essentially what it seems to be is | + | == A practical Cont tutorial == |

+ | |||

+ | It seems to me like <hask>Cont</hask> and <hask>ContT</hask> is way simpler than people make it. Essentially what it seems to be is a way to give a name to the "tail" of a do-block. | ||

<haskell> | <haskell> | ||

Line 9: | Line 11: | ||

thing2 | thing2 | ||

-- Here I want to manipulate the rest of the computation. | -- Here I want to manipulate the rest of the computation. | ||

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

-- play with. | -- play with. | ||

magic $ \rest -> | magic $ \rest -> | ||

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

+ | -- or do it twice, or discard it, or | ||

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

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

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

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

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

Line 46: | Line 50: | ||

Now what? Well, remember what <hask>g</hask> is. 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: | Now what? Well, remember what <hask>g</hask> is. 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> | <haskell> | ||

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

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

Line 74: | Line 78: | ||

</haskell> | </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>. | + | <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". I don't really get the name. 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? === | === What about ContT? === | ||

Line 89: | Line 110: | ||

The only reason the newtype exists at all is to make the kind compatible with things like <hask>MonadTrans</hask>. | The only reason the newtype exists at all is to make the kind compatible with things like <hask>MonadTrans</hask>. | ||

+ | |||

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

+ | |||

+ | The examples in the mtl doc are unconvincing. They don't do anything genuinely daring. Some of them work in any monad! Here's a more complex example: | ||

+ | |||

+ | <haskell> | ||

+ | -- This tends to be useful. Don't ask about the name. | ||

+ | reset :: Cont a a -> a | ||

+ | reset c = runCont c id | ||

+ | |||

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

+ | faff n = reset $ 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> | ||

+ | |||

+ | 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, work out how to make the function return (a) <hask>Nothing</hask>, (b) <hask>Just 12</hask>, (c) <hask>Just 0</hask>. |

## Revision as of 23:36, 19 January 2012

I found a bug with the <hask> tag. I put it on its own page so it doesn't ruin my user page.

## Contents |

## 1 A practical Cont tutorial

It seems to me likeCont

ContT

contstuff :: Magic a contstuff = do thing1 thing2 -- Here 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, or discard it, or -- do it and then use the result to do it again... it's easy to -- imagine why this might be useful. thing3 -- these might get done once, several times, thing4 -- or not at all.

magic

r

magic

r

r

magic

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

x

magic

a -> r

r

(a -> r) -> r

magic :: (a -> r) -> r -> Magic a

Magic a = Cont r a magic = Cont

Tada!

The thing withCont

Functor

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

Cont

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

g

\rest -> stuffWith (rest val)

val

<-

rest

f

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

Applicative

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 -> -- ...

fmap

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

Monad

runCont

case

let

### 1.1 So what's callCC?

"Call with current continuation". I don't really get the name. Basically, you usecallCC

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!"

*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

exit

runCont

### 1.2 What about ContT?

The thing withContT

*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

MonadTrans

### 1.3 Some real examples

The examples in the mtl doc are unconvincing. They don't do anything genuinely daring. Some of them work in any monad! Here's a more complex example:

-- This tends to be useful. Don't ask about the name. reset :: Cont a a -> a reset c = runCont c id faff :: Integer -> Maybe Integer faff n = reset $ 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

return

test = n

(2*n)

Nothing

Just 12

Just 0