Re: [Haskell-cafe] Can we come out of a monad?

From: Alexey Khudyakov
On Fri, 30 Jul 2010 09:29:59 +0200 Stefan Holdermans
wrote: No I think here we breaking out from _arbitrary_ monad. If monadic function works for every monad then it must work for identity monad too. Here is simplest form of purify function:
purify2 :: (forall m . Monad m => m a) -> a purify2 m = runIdentity m
I wonder could this function be written without resorting to concrete monad
I don't find purify2 particularly helpful because I almost never want to break out of any arbitrary monad; I want to be able to break out of a specific monad without knowing which monad it is, that is: purify3 :: Monad m => m a -> a purify3 = undefined --the only possible definition... However, I just realized that something else is almost as good: evalCont :: Cont r a -> r evalCont k = runCont k id As Cont is the "Mother of all monads", it can be used to emulate the behavior of any other monad. If you had a library with instances of MonadReader, MonadWriter, MonadState, etc. (or operational equivalents) defined for the Cont monad, then you would have a purify function that works for all interesting monads (except IO, STM, and maybe ST), which is almost as good. John

On Monday 09 August 2010 21:19:01, John Lato wrote:
I don't find purify2 particularly helpful because I almost never want to break out of any arbitrary monad; I want to be able to break out of a specific monad without knowing which monad it is, that is:
purify3 :: Monad m => m a -> a purify3 = undefined --the only possible definition...
Just to be obnoxious: purify3 = const undefined ;)
However, I just realized that something else is almost as good:
evalCont :: Cont r a -> r evalCont k = runCont k id
Wouldn't you want the signature Cont r a -> a to break out? Also: ContBreak.hs:6:23: Couldn't match expected type `r' against inferred type `a' `r' is a rigid type variable bound by the type signature for `evalCont' at ContBreak.hs:5:17 `a' is a rigid type variable bound by the type signature for `evalCont' at ContBreak.hs:5:19 In the second argument of `runCont', namely `id' In the expression: runCont k id In the definition of `evalCont': evalCont k = runCont k id evalCont :: (forall r. Cont r a) -> a evalCont k = runCont k id would work (but is something different).
As Cont is the "Mother of all monads", it can be used to emulate the behavior of any other monad. If you had a library with instances of MonadReader, MonadWriter, MonadState, etc. (or operational equivalents) defined for the Cont monad, then you would have a purify function that works for all interesting monads (except IO, STM, and maybe ST), which is almost as good.
John

On Mon, Aug 9, 2010 at 1:19 PM, John Lato
I don't find purify2 particularly helpful because I almost never want to break out of any arbitrary monad; I want to be able to break out of a specific monad without knowing which monad it is, that is:
purify3 :: Monad m => m a -> a purify3 = undefined --the only possible definition...
However, I just realized that something else is almost as good:
evalCont :: Cont r a -> r evalCont k = runCont k id
Except, of course, you want the signature evalCont :: Cont r a -> a Which is not possible. But I am not sure where all this discussion is coming from, Maybe and (r ->) cannot be broken out of. Isn't that example enough? Luke

Excerpts from Luke Palmer's message of Tue Aug 10 01:04:04 -0400 2010:
Except, of course, you want the signature
evalCont :: Cont r a -> a
Which is not possible. But I am not sure where all this discussion is coming from, Maybe and (r ->) cannot be broken out of. Isn't that example enough?
I'm confused... that's the type of evalCont, no? Cheers, Edward

"Edward Z. Yang"
Excerpts from Luke Palmer's message of Tue Aug 10 01:04:04 -0400 2010:
Except, of course, you want the signature
evalCont :: Cont r a -> a
Which is not possible. But I am not sure where all this discussion is coming from, Maybe and (r ->) cannot be broken out of. Isn't that example enough?
I'm confused... that's the type of evalCont, no?
There is no evalCont, there is runCont: runCont :: (a -> r) -> Cont r a -> r Note that Cont/ContT computations result in a value of type 'r': newtype Cont r a = Cont ((a -> r) -> r) Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/

Excerpts from Ertugrul Soeylemez's message of Tue Aug 10 02:31:14 -0400 2010:
There is no evalCont, there is runCont:
runCont :: (a -> r) -> Cont r a -> r
Note that Cont/ContT computations result in a value of type 'r':
newtype Cont r a = Cont ((a -> r) -> r)
Yes, but if you pass in 'id' as the continuation to 'runCont', the entire expression will result in 'a'. The continuation monad doesn't act globally... Still confused, Edward

"Edward Z. Yang"
Excerpts from Ertugrul Soeylemez's message of Tue Aug 10 02:31:14 -0400 2010:
There is no evalCont, there is runCont:
runCont :: (a -> r) -> Cont r a -> r
Note that Cont/ContT computations result in a value of type 'r':
newtype Cont r a = Cont ((a -> r) -> r)
Yes, but if you pass in 'id' as the continuation to 'runCont', the entire expression will result in 'a'. The continuation monad doesn't act globally...
Then you can only run evalCont, if r = a, which makes that function quite pointless: evalCont :: Cont r r -> r evalCont = runCont id Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/

Excerpts from Ertugrul Soeylemez's message of Tue Aug 10 03:40:02 -0400 2010:
Then you can only run evalCont, if r = a, which makes that function quite pointless:
evalCont :: Cont r r -> r evalCont = runCont id
Ah, yes, that was what I was imagining. I don't think the function is useless (though it is pointless ;-); it lets you transform continuation-style code into normal code. Also, r is usually not fixed (unless you use mapCont or similar), so it might be more accurately described as Cont a a -> a. Cheers, Edward

"Edward Z. Yang"
Excerpts from Ertugrul Soeylemez's message of Tue Aug 10 03:40:02 -0400 2010:
Then you can only run evalCont, if r = a, which makes that function quite pointless:
evalCont :: Cont r r -> r evalCont = runCont id
Ah, yes, that was what I was imagining. I don't think the function is useless (though it is pointless ;-); it lets you transform continuation-style code into normal code. Also, r is usually not fixed (unless you use mapCont or similar), so it might be more accurately described as Cont a a -> a.
My point was, I would just write 'runCont id'. ;) The result type of the computation is fixed. It cannot change between (>>=). Note that 'a' is the result of one subcomputation, i.e. the result of one particular CPS-style function, while 'r' is the result of the entire computation. So runCont should give you an 'r', not an 'a'. In this case, they just happen to be the same. But of course this is really a matter of taste. =) Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/

On Tue, Aug 10, 2010 at 6:48 AM, Edward Z. Yang
Excerpts from Luke Palmer's message of Tue Aug 10 01:04:04 -0400 2010:
Except, of course, you want the signature
evalCont :: Cont r a -> a
Which is not possible. But I am not sure where all this discussion is coming from, Maybe and (r ->) cannot be broken out of. Isn't that example enough?
I'm confused... that's the type of evalCont, no?
Except that I messed up and "evalCont" doesn't compile. The type would have to be evalCont :: Cont a a -> a
participants (5)
-
Daniel Fischer
-
Edward Z. Yang
-
Ertugrul Soeylemez
-
John Lato
-
Luke Palmer