
Given this:
class (Monad m) => PeirceMonad m where { peirceM :: ((a -> m b) -> m a) -> m a; };
...which Monads can be made PeirceMonads?
Here's one: data ContMonad p a = MkContMonad ((a -> p) -> p); unContMonad (MkContMonad app) = app; instance Monad (ContMonad p) where { return a = MkContMonad (\cont -> cont a); (MkContMonad ma) >>= bf = MkContMonad (\cont -> ma (\a -> unContMonad (bf a) cont)); }; instance PeirceMonad m where { peirceM foo = MkContMonad (\cont -> unContMonad (foo (\a -> MkContMonad (\_ -> (cont a)))) cont); }; doContMonad :: ContMonad p p -> p; doContMonad cm = unContMonad cm id; test1 = doContMonad (peirceM (\continuation -> do { continuation 1; continuation 2; continuation 3; })); -- returns 1 Now here's the interesting thing. The usual way to represent "real-world" functions (i.e. with side-effects, or changing the world) from a to b is to define a special _type constructor_, 'IO', and define the function as 'a -> IO b'. But an alternative, would have been to define a special _type_, Action, and define the function as 'a -> (b -> Action) -> Action'. And then your 'main' function has type 'Action'. Nor do we have to declare special >>= and return functions as we do for IO. Here's how it's equivalent: type Action = IO (); type ActionMonad = ContMonad Action; doActionMonad :: ActionMonad () -> Action; doActionMonad cm = unContMonad cm return; liftIO :: IO a -> ActionMonad a; liftIO ioa = MkContMonad (\cont -> ioa >>= cont); ...and note that we get Peirce continuations for free: peirce foo cont = foo (\a _ -> (cont a)) cont; -- constructors removed -- Ashley Yakeley, Seattle WA

Ashley Yakeley writes:
Now here's the interesting thing. The usual way to represent "real-world" functions (i.e. with side-effects, or changing the world) from a to b is to define a special _type constructor_, 'IO', and define the function as 'a -> IO b'. But an alternative, would have been to define a special _type_, Action, and define the function as 'a -> (b -> Action) -> Action'. And then your 'main' function has type 'Action'.
Nor do we have to declare special >>= and return functions as we do for IO.
Yeah, it's called continuation-passing style (CPS). (b -> Action) is the type of the continuation argument.
...and note that we get Peirce continuations for free:
peirce foo cont = foo (\a _ -> (cont a)) cont; -- constructors removed
Yeah, in CPS, call/cc is easy to write. So, congratulations, you've written call/cc in Haskell. I think. So, what I said this afternoon, namely, that call/cc is "not something an implementation is likely to be able to support unintentionally", I now have to retract. I think. I guess the call/cc you wrote last night in terms of catch and a ref didn't work too well; huh?
participants (2)
-
Ashley Yakeley
-
Richard Uhtenwoldt