How to make callCC more dynamic?

I thought the correct type for ContT should be

newtype ContT ma = ContT {runContT :: forall r. (a -> mr) -> mr} 

and other control operators

 shift :: Monad m => (forall r. (a -> ContT mr) -> ContT mr) -> ContT ma reset :: Monad m => ContT ma -> ContT ma callCC :: ((a -> (forall r. ContT mr)) -> ContT ma) -> ContT ma 

Unfortunately, I cannot perform a callCC type callCC and do not know how to do this. I was able to perform a check like shift and reset

 reset :: Monad m => ContT ma -> ContT ma reset e = ContT $ \ k -> runContT e return >>= k shift :: Monad m => (forall r. (a -> ContT mr) -> ContT mr) -> ContT ma shift e = ContT $ \ (k :: a -> mr) -> runContT ((e $ \ v -> ContT $ \c -> kv >>= c) :: ContT mr) return 

but still, I cannot use shift and reset in a recursive jump, how is it?

 newtype H rm = H (H rm -> ContT mr) unH (H x) = x test = flip runContT return $ reset $ do jump <- shift (\f -> f (H f)) lift . print $ "hello" unH jump jump 

Has anyone tried this before?

+20
haskell continuations callcc
Aug 24 '11 at 16:23
source share
2 answers

Do you want to play a game ?

Today you will receive callCC .

 callCC :: ((a -> (forall r. ContT mr)) -> ContT ma) -> ContT ma -- you are here ^^ 

Everything to the left of this arrow of the function is the movements that your opponent made. To the right of the arrow is the end of the game. To win, you must build something that corresponds to the right side, using only the items that your opponent has provided.

Fortunately, you still have some words in deeds. See this arrow here?

 callCC :: ((a -> (forall r. ContT mr)) -> ContT ma) -> ContT ma -- this is your opponent ^^ 

When you get something that contains an arrow, everything to the left of it is the steps you take and the part to the right of the end of this game branch, giving you another piece that you can use as part of yours (I hope ) winning strategy.

Before moving on, simplify a few things: the monad transformer aspect is just a distraction, so drop it; and add explicit quantifiers for each type variable.

 callCC :: forall a. ((a -> (forall b. Cont b)) -> Cont a) -> Cont a 

Now think of a type like forall a. ... forall a. ... If you produce something like this type, you say you can provide a value for any type a in general. If you get something with a similar type, you can choose a specific type to use. Compare this to a type of type A -> ... for a monomorphic function; when creating such a function, you say that you know how to provide a result for any value of type a , while obtaining such a function allows you to select the specific value of a to use. This is similar to the situation with forall , and in fact, parallta is executed. Thus, we can consider forall as an indication of the movement in which you or your opponent acquires a type, not a term. To reflect this, I will abuse the notation and write forall a. ... forall a. ... like a => ; we can handle it the same way as (->) , except that it should appear to the left of any applications of the associated type variable.

It can also be noted that the only thing that can be done directly with a value of type Cont a is to apply runCont to it. Therefore, we will do this in advance and enter all the relevant quantifiers directly into the type for callCC .

 callCC :: a => ( (a -> (b => (r1 => (b -> r1) -> r1))) -> (r2 => (a -> r2) -> r2) ) -> (r3 => (a -> r3) -> r3) 

Since we can treat forall in the same way as other function arrows, we can reorder things and remove the extra parentheses to work a bit. In particular, note that callCC is not really the end of the game, as it turns out; we must provide a function that boils down to providing another game in which we will again play the role of the rightmost arrow. Thus, we can keep the step by combining them. I will also use arguments like float on the left to get them all in one place.

 callCC :: a => r3 => (a -> r3) -> (r2 => (b => r1 => a -> (b -> r1) -> r1) -> (a -> r2) -> r2) -> r3 

So ... our move.

We need something like r3 . Our opponent made four moves that we received as arguments. One step is to choose r3 , so we are already at a disadvantage. Another move is a -> r3 , which means that if we can play a , our opponent will cough r3 , and we will be able to win. Unfortunately, our opponent also played a , so we returned to where we started. We will need something like a or some other way to get something like r3 .

The last step made by our opponent is more difficult, so we will consider it alone:

 r2 => (b => r1 => a -> (b -> r1) -> r1) -> (a -> r2) -> r2 

Remember that this is the step they took. So, the rightmost arrow here represents our opponent, and everything on the left represents the type of movements we can make. The result of this is something like r2 , where r2 is what we play. Therefore, we must play either r3 or a to make any progress.

Game a : If we play a as r2 , then we can play id as a -> r2 . The other move is more complicated, so we will move inside this one.

 b => r1 => a -> (b -> r1) -> r1 

Back to the rightmost arrow representing us. This time we need to produce something like r1 , where r1 is the step that the opponent took. They also played the function b -> r1 , where type b was also the step they took. So we need something like type b or r1 . Unfortunately, all they gave us was something like a , leaving us in an impregnable position. Guess that playing a used to be a bad choice. Try again...

Game r3 : If we play r3 as r2 , we also need to play the function a -> r3 ; fortunately, the adversary has already played such a function, so we can just use it. Once again, jump into another movement:

 b => r1 => a -> (b -> r1) -> r1 

... only to find that this is exactly the same impossible situation as before. Being at the mercy of the choice of the opponent r1 , not demanding that they provide a way of construction, we find ourselves in a trap.

Perhaps a little cheating will help?

Bend Rules - Play r1 :

We know that in regular Haskell, we can rely on laziness to twist things and allow computing to learn its own tail. Without worrying too much about how, suppose we can do the same here - take r1 , which our opponent plays in the internal game, and pull it out and come back to play it like r2 .

Once again, here the adversary moves:

 r2 => (b => r1 => a -> (b -> r1) -> r1) -> (a -> r2) -> r2 

After we connect the nodes to the nodes, this ends with the equivalent of this:

 (b => a -> (b -> r1) -> r1) -> (a -> r1) -> r1 

Arguments like this have disappeared thanks to our deception, but r1 is still chosen by the adversary. So, all that we have achieved here is shuffling things; we cannot even hope to get a or r3 from him, so we hit another dead end.

So, we make one final, desperate attempt:

Bend Rules - Playback b :

This time we take b which the opponent plays in the innermost game and loop to play like r2 . Now the enemyโ€™s movement is as follows:

 (r1 => a -> (b -> r1) -> r1) -> (a -> b) -> b 

And again in the inner game:

 r1 => a -> (b -> r1) -> r1 

Continuing the deception, we can twist the result of b higher, and also, to give the function b -> r1 , we need r1 . Success!

Having retreated, we still have one problem. We need to play something like a -> b . There is no obvious way to find it, but we already have b , so we can just use const to drop a and -

- but wait. Where does this type b value come first? In short, in our shoes against the opponent, the only places where they can get are the result of the actions we do. If only b we have the one that they give us, we end up in circles; the game never ends.




So, in the game callCC only strategies that we led to the loss or permanent impasse.

 callCC :: forall a. ((a -> (forall b . Cont b)) -> Cont a) -> Cont a callCC = error "A strange game..." 

Alas, it seems that the only winning move is not to play.

+26
Aug 24 '11 at 18:05
source share

Although there is no way to win this game, if we spin the game a bit, we can win!

 newtype ContT' ma = ContT' { runContT' :: forall r. (Maybe a -> m (Maybe r)) -> m (Maybe r) } 

As we saw in another answer, the problem is to win, we must generate a value for the arbitrary type that our opponent played, but we do not know how to do it.

By forcing all raw types ( r and a ) to be Decorated with Maybe , we can circumvent this problem and can generate the value of any Maybe t - just give Nothing them!

We must show that it is Monad .

 instance Monad m => Monad (ContT' m) where return a = ContT' $ \k -> k (Just a) a >>= f = ContT' $ \c -> runContT' a ( maybe (return Nothing) (\v -> runContT' (fv) c)) 

And then we can implement callCC :

 class Monad m => MonadCont' m where callCC' :: ((a -> forall bm b) -> ma) -> ma instance Monad m => MonadCont' (ContT' m) where callCC' k = ContT' $ \c -> runContT' (k (\a -> ContT' $ \_ -> c (Just a) >> return Nothing)) c 

I am still developing how to implement reset and shift .

0
Jun 17 '14 at 11:56
source share



All Articles