[Haskell-cafe] Re: Different choice operations in a continuation
monad
Heinrich Apfelmus
apfelmus at quantentunnel.de
Fri Jun 18 12:37:12 EDT 2010
Heinrich Apfelmus wrote:
> Sebastian Fischer wrote:
>
>> For example, the implementation of
>> `callCC` does not type check with your changed data type.
>
> [snip]
>
> As for the interaction: what should
>
> ((callCC ($ 0) >> mzero) `orElse` return 2) >>= return . (+3)
>
> be? If the scope of callCC should not extend past orElse , then this
> evaluates to return 5 . But this choice of scope dictates the type that
> Holger mentioned.
>
> If the the scope of callCC should extend beyond the orElse , so that
> the whole thing evaluates to mzero , orElse will have the type of
> mplus . But then, I think that your implementation type CMaybe needs
> to be more sophisticated because orElse now needs to detect whether
> the argument contains a call to callCC or not in order to distinguish
>
> ((callCC ($ 0) >> mzero) `orElse` return 2) >>= return . (+3)
>
> ==> mzero
>
> from
>
> (mzero `orElse` return 2) >>= return . (+3)
>
> ==> return 5
Out of curiosity, I've implemented these semantics with operational .
Code attached.
Took me a while to figure out how to implement callCC , but it turns
out to be straightforward if you simply carry around the current
continuation as an additional parameter.
It doesn't seem to be possible to implement this with just the CMaybe r
a type, in particular since the implementation I gave cannot be
refunctionalized to said type. In other words, there is probably no
associative operation
orElse :: CMaybe r a -> CMaybe r a -> CMaybe r a
with identity `mzero` that satisfies the cancellation law. I don't have
a proof, but the argument that it doesn't interact well with the default
implementation of callCC seems strong to me.
Regards,
Heinrich Apfelmus
--
http://apfelmus.nfshost.com
-------------- next part --------------
{-----------------------------------------------------------------------------
A small language with both a choice operationa orElse and callCC
In response to
http://www.haskell.org/pipermail/haskell-cafe/2010-June/079029.html
------------------------------------------------------------------------------}
{-# LANGUAGE GADTs, RankNTypes, TypeSynonymInstances, FlexibleInstances #-}
import Control.Monad.Identity
import Control.Monad
import Control.Monad.Operational
{-----------------------------------------------------------------------------
Language definition
------------------------------------------------------------------------------}
-- primitive instructions
data Instruction r a where
CallCC :: ((forall b. a -> M r b) -> M r a) -> Instruction r a
Jump :: M r r -> Instruction r a
OrElse :: M r a -> M r a -> Instruction r a
MZero :: Instruction r a
jump = singleton . Jump -- not exported, needed to implement callCC
callCC = singleton . CallCC
orElse m n = singleton (OrElse m n)
instance MonadPlus (ProgramT (Instruction r) Identity) where
mzero = singleton MZero
mplus = undefined -- ignore
-- main type
type M r a = Program (Instruction r) a
-- examples
example1, example2 :: M Int Int
example1 = ((callCC (\k -> k 0) >> mzero) `orElse` return 2) >>= return . (+3)
example2 = (mzero `orElse` return 2) >>= return . (+3)
{-----------------------------------------------------------------------------
Interpreter
------------------------------------------------------------------------------}
-- global interpreter
interpret :: M r r -> Maybe r
interpret m = case (eval return . view) m of
JumpR mr -> interpret mr
ReturnR a -> Just a
MZeroR -> Nothing
-- helper type for the interpreter
data Result r a where
ReturnR :: a -> Result r a
MZeroR :: Result r a
JumpR :: M r r -> Result r a
-- local interpreter
-- Passes around the current continuation kk so that we can
-- implement callCC , but never continues evaluation with kk
eval :: (a -> M r r) -> ProgramView (Instruction r) a -> Result r a
eval kk (Return a) = ReturnR a
eval kk (CallCC f :>>= k) = (eval kk . view) $ f (jump . kk') >>= k
where kk' = k >=> kk
eval kk (OrElse n m :>>= k) = case (eval kk' . view) n of
ReturnR a -> (eval kk . view) (k a)
JumpR mr -> JumpR mr
MZeroR -> (eval kk . view) (m >>= k)
where kk' = k >=> kk
eval kk (MZero :>>= k) = MZeroR
eval kk (Jump mr :>>= k) = JumpR mr
More information about the Haskell-Cafe
mailing list