
Is there any way to do a lazy bind operation, something like a <- $ getLine return (Constructor $ a) this works for computations in the IO monad :- a <- unsafeInterleaveIO getLine return (Constructor $ a) but I need to do this for a general monad M. Keean Schupke Department of Electrical & Electronic Engineering, Imperial College London.

tis 2002-07-30 klockan 14.41 skrev MR K P SCHUPKE:
Is there any way to do a lazy bind operation, something like
a <- $ getLine return (Constructor $ a)
this works for computations in the IO monad :-
a <- unsafeInterleaveIO getLine return (Constructor $ a)
but I need to do this for a general monad M.
Remember that the syntax a <- getLine return (Constructor a) is just sugar for getLine >>= \a -> return (Constructor a) so actually the bind is already lazy (lamba binding is lazy). The laziness of the construction here will depend on your definition of >>= for the monad in question. Since the point of the IO monad is to sequentialize IO operations, >>= will definititely not be lazy there. Perhaps if you give a concrete example of what you want to do, people could help you more. Regards, Martin -- Martin Norbäck d95mback@dtek.chalmers.se Kapplandsgatan 40 +46 (0)708 26 33 60 S-414 78 GÖTEBORG http://www.dtek.chalmers.se/~d95mback/ SWEDEN OpenPGP ID: 3FA8580B

Okay here goes... I am trying to write a monad-transformer for a consumer based parser. As such the normal (non monad-transformer version) would look like: (Parser p) >>= q = Parser $ \cs -> case p cs of Rejected -> Rejected Accepted accept -> Accepted $ case accept of Fail y -> Fail y Empty -> Empty Ok cs' x -> case (\(Parser z) -> z) (q x) cs' of Accepted c' -> c' Rejected -> Fail noMsg however when rewriting as a monad transformer we end up with:- (ParserT p) >>= q = ParserT $ \cs -> do a <- p cs case a of Rejected -> return Rejected Accepted accept -> do reply <- case accept of Fail y -> return (Fail y) Empty -> return (Empty) Ok cs' x -> do b <- runParserT (q x) cs' case b of Accepted c' -> return c' Rejected -> return (Fail noMsg) return (Accepted $ reply) if we run a computation in say (ParserT IO) the Accepted is not returned until after the last IO operation... whereas what I want is the accepted returned ASAP, with the full reply after the last IO operation. I have tried defining liftIO as the following: liftIO = lift . liftIO . unsafeInterleaveIO but this is too lazy as IO operations don't get run until their result is used. what I really need is to replace the bind: "reply <- case accept of" with "reply <- $ case accept of" (which of course is not valid). The alternative is to produce a specialised instance for (ParserT IO) using "reply <- unsafeInterleaveIO $ case accept of" but this is not a general solution as it does not deal with (ParserT SomeMonadT IO) etc... Keean Schupke Department of Electrical & Electronic Engineering, Imperial College London. Martin Norbäck wrote:
Remember that the syntax
a <- getLine return (Constructor a)
is just sugar for
getLine >>= \a -> return (Constructor a)
so actually the bind is already lazy (lamba binding is lazy). The laziness of the construction here will depend on your definition of >>= for the monad in question. Since the point of the IO monad is to sequentialize IO operations, >>= will definititely not be lazy there.
Perhaps if you give a concrete example of what you want to do, people could help you more.
Regards,
Martin
-- Martin Norbäck d95mback@dtek.chalmers.se Kapplandsgatan 40 +46 (0)708 26 33 60 S-414 78 GÖTEBORG http://www.dtek.chalmers.se/~d95mback/ SWEDEN OpenPGP ID: 3FA8580B
------------------------------------------------------------------------
signature.ascName: signature.asc Type: application/pgp-signature

Can you please give your definition of the Parser and ParserT type constructors? My guesses are: data State = ... data Message = ... data Accept a = Fail Message | Empty | Ok State a data Decide a = Rejected | Accepted a data Parser a = Parser (State -> Decide (Accept a)) data ParserT m a = Parser (State -> m (Decide (Accept a))) I wonder if it wouldn't be possible to redefine ParserT as data ParserT m a = Parser (State -> m (Decide (m (Accept a)))) ? -- Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig The trick is that there is no trick.

The data types I used are: data (Error e) => Reply e s a= Ok [s] a | Empty | Fail e data (Error e) => Result e s a = Accepted (Reply e s a) | Rejected newtype (Error e) => Parser e s a = Parser {runParser :: [s] -> Result e s a} newtype (Error e,Monad m) => ParserT e s m a = ParserT {runParserT :: [s] -> m (Result e s a)} data ParserError = UnspecifiedError | ErrorMsg String deriving Show instance Error ParserError where noMsg = UnspecifiedError strMsg s = ErrorMsg s Hope this makes things clearer... Regards, Keean Schupke Department of Electrical & Electronic Engineering, Imperial College London. Ken Shan wrote:
Can you please give your definition of the Parser and ParserT type constructors? My guesses are:
data State = ... data Message = ... data Accept a = Fail Message | Empty | Ok State a data Decide a = Rejected | Accepted a
data Parser a = Parser (State -> Decide (Accept a)) data ParserT m a = Parser (State -> m (Decide (Accept a)))
I wonder if it wouldn't be possible to redefine ParserT as
data ParserT m a = Parser (State -> m (Decide (m (Accept a))))
?
-- Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig The trick is that there is no trick.
------------------------------------------------------------------------ Part 1.2Type: application/pgp-signature

On 2002-07-30T18:43:28+0100, MR K P SCHUPKE wrote:
The data types I used are:
data (Error e) => Reply e s a= Ok [s] a | Empty | Fail e data (Error e) => Result e s a = Accepted (Reply e s a) | Rejected
newtype (Error e) => Parser e s a = Parser {runParser :: [s] -> Result e s a}
newtype (Error e,Monad m) => ParserT e s m a = ParserT {runParserT :: [s] -> m (Result e s a)}
[...]
Hope this makes things clearer...
Yes! Let me rephrase my earlier suggestion in terms of these actual types. For reasons that will soon become clear, let me begin by rearranging Result a bit: data Result x = Accepted x | Rejected newtype (Error e) => Parser e s a = Parser {runParser :: [s] -> Result (Reply e s a)} newtype (Error e, Monad m) => ParserT e s m a = ParserT {runParserT :: [s] -> m (Result (Reply e s a))} (Here I have removed the constraint "Error e" from the definition of Result. I don't think it will cause you much trouble.) Now, what about the following alternative definition of ParserT? newtype (Error e, Monad m) => ParserT e s m a = ParserT {runParserT :: [s] -> m (Result (m (Reply e s a)))} Would it suit your purposes? -- Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig When was the last time you wrote your representative in government? And, vote, for those who can't.

Hi Ken, Thankyou for having a look at this for me. I have implemented the type as: newtype (Error e,Monad m) => ParserT e s m a = PT {runParserT :: [s] -> m (Result e s m a)} data (Error e) => Result e s m a = Accepted (m (Reply e s a)) | Rejected data (Error e) => Reply e s a = Ok [s] a | Empty | Fail e Having changed the instances of Monad/MonadPlus for this type, I can confirm it works perfectly - I see how the nested Monad allows you to continue the computation in the 'bind' operator whilst still returning 'Accepted'. I think this is a lot better than the solution I had working, which involved a new subclass of Monad, defining the function 'lbind' to be just >>= for all monads apart from IO where is was: lbind j k = unsafeInterleaveIO $ j >>= k. I then used lbind to bind the result of "runParserT (k x) cs'" in the '>>=' function for ParserT... Thanks again, Keean Schupke Department of Electrical & Electronic Engineering, Imperial College London. -----Original Message----- From: glasgow-haskell-users-admin@haskell.org [mailto:glasgow-haskell-users-admin@haskell.org]On Behalf Of Ken Shan Sent: 01 August 2002 06:08 To: MR K P SCHUPKE Cc: glasgow-haskell-users@haskell.org Subject: Re: Lazy bind... Yes! Let me rephrase my earlier suggestion in terms of these actual types. For reasons that will soon become clear, let me begin by rearranging Result a bit: data Result x = Accepted x | Rejected newtype (Error e) => Parser e s a = Parser {runParser :: [s] -> Result (Reply e s a)} newtype (Error e, Monad m) => ParserT e s m a = ParserT {runParserT :: [s] -> m (Result (Reply e s a))} (Here I have removed the constraint "Error e" from the definition of Result. I don't think it will cause you much trouble.) Now, what about the following alternative definition of ParserT? newtype (Error e, Monad m) => ParserT e s m a = ParserT {runParserT :: [s] -> m (Result (m (Reply e s a)))} Would it suit your purposes? -- Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig When was the last time you wrote your representative in government? And, vote, for those who can't.

On Tue, Jul 30, 2002 at 01:41:43PM +0100, MR K P SCHUPKE wrote:
Is there any way to do a lazy bind operation, something like
a <- $ getLine return (Constructor $ a)
this works for computations in the IO monad :-
a <- unsafeInterleaveIO getLine return (Constructor $ a)
but I need to do this for a general monad M.
I don't think this is possible. In general, you have to write separate strict and lazy binding operations. For instance, there are both ST and LazyST for state transformer monads, and the latter's >>= operation is lazy. Here's a concrete example for the basic state-carrying monad. (Not tested) newtype State s a = State { unState :: s -> (a, s) } getState = State (\s -> (s, s)) setState x = State (\s -> ((), x)) -- Monad.return returnState a = State (\s -> (a, s)) -- strict Monad.>>= State m `strictBindState` f = State (\s -> case m s of (a, s') -> unState (f a) s') -- lazy Monad.>>= State m `lazyBindState` f = State (\s -> case m s of ~(a, s) -> unState (f a) s') As you can see, the difference between lazy and strict binding is an inherent part of the definition of >>=, so there's no way to automatize it. This is kind of a shame, for I too sometimes need both lazy and strict versions of a monad transformer, but this requires two separate types with different monad instances... Lauri Alanko la@iki.fi

fre 2002-08-02 klockan 14.57 skrev Lauri Alanko:
On Tue, Jul 30, 2002 at 01:41:43PM +0100, MR K P SCHUPKE wrote:
Is there any way to do a lazy bind operation, something like
a <- $ getLine return (Constructor $ a)
this works for computations in the IO monad :-
a <- unsafeInterleaveIO getLine return (Constructor $ a)
but I need to do this for a general monad M.
I don't think this is possible. In general, you have to write separate strict and lazy binding operations. For instance, there are both ST and LazyST for state transformer monads, and the latter's >>= operation is lazy.
Here's a concrete example for the basic state-carrying monad. (Not tested)
newtype State s a = State { unState :: s -> (a, s) } getState = State (\s -> (s, s)) setState x = State (\s -> ((), x)) -- Monad.return returnState a = State (\s -> (a, s)) -- strict Monad.>>= State m `strictBindState` f = State (\s -> case m s of (a, s') -> unState (f a) s') -- lazy Monad.>>= State m `lazyBindState` f = State (\s -> case m s of ~(a, s) -> unState (f a) s')
As you can see, the difference between lazy and strict binding is an inherent part of the definition of >>=, so there's no way to automatize it. This is kind of a shame, for I too sometimes need both lazy and strict versions of a monad transformer, but this requires two separate types with different monad instances...
Perhaps just some more syntactic sugar would be in order. Say something like this: infixl 1 >>=$ class Monad m => LazyMonad m where (>==$) :: m a -> (a -> m b) -> m b and then make a <-$ m use >==$ instead of >>=. The operator names are just meant as an example of course. Regards, Martin -- Martin Norbäck d95mback@dtek.chalmers.se Kapplandsgatan 40 +46 (0)708 26 33 60 S-414 78 GÖTEBORG http://www.dtek.chalmers.se/~d95mback/ SWEDEN OpenPGP ID: 3FA8580B
participants (5)
-
Keean
-
Ken Shan
-
Lauri Alanko
-
Martin Norbäck
-
MR K P SCHUPKE