WriterT [w] IO is not lazy in reading [w]

As someone suggested me, I can read the logs from Writer and WriterT as computation goes by, if the monoid for the Writer is lazy readable. This has been true until I tried to put the IO inside WriterT
{-# LANGUAGE FlexibleContexts #-} import Control.Monad.Writer
k :: (MonadWriter [Int] m) => m [Int] k = let f x = tell [x] >> f (x + 1) in f 0
works :: [Int] works = snd $ runWriter k
hangs :: IO [Int] hangs = snd `liftM` runWriterT k
main = take 20 `liftM` hangs >>= print
The main hangs both interpreted and compiled on ghc 6.10.1. The issue is not exposing with IO alone as main = print "test" >> main is a working program. Thanks for explanations. paolino

On Wed, 2008-12-31 at 21:48 +0100, Paolino wrote:
As someone suggested me, I can read the logs from Writer and WriterT as computation goes by, if the monoid for the Writer is lazy readable. This has been true until I tried to put the IO inside WriterT
{-# LANGUAGE FlexibleContexts #-} import Control.Monad.Writer
k :: (MonadWriter [Int] m) => m [Int]
k = let f x = tell [x] >> f (x + 1) in f 0
works :: [Int] works = snd $ runWriter k
hangs :: IO [Int] hangs = snd `liftM` runWriterT k
runWriterT :: MonadWriter w m a => WriterT w m a -> m (a, w) which is to say runWriterT k :: IO (a, [Int]) It's not going to return anything until the IO action terminates, which is to say never.

I must ask why runWriterT k :: State s (a,[Int]) is working.
Looks like I could runIO the same way I evalState there.
In that case I wouldn't wait for the State s action to finish.
Thanks
2008/12/31 Derek Elkins
On Wed, 2008-12-31 at 21:48 +0100, Paolino wrote:
As someone suggested me, I can read the logs from Writer and WriterT as computation goes by, if the monoid for the Writer is lazy readable. This has been true until I tried to put the IO inside WriterT
{-# LANGUAGE FlexibleContexts #-} import Control.Monad.Writer
k :: (MonadWriter [Int] m) => m [Int]
k = let f x = tell [x] >> f (x + 1) in f 0
works :: [Int] works = snd $ runWriter k
hangs :: IO [Int] hangs = snd `liftM` runWriterT k
runWriterT :: MonadWriter w m a => WriterT w m a -> m (a, w)
which is to say runWriterT k :: IO (a, [Int])
It's not going to return anything until the IO action terminates, which is to say never.

2008/12/31 Paolino
I must ask why runWriterT k :: State s (a,[Int]) is working. Looks like I could runIO the same way I evalState there. In that case I wouldn't wait for the State s action to finish.
Thanks
Assuming you have Control.Monad.State.Lazy (which I think is the default), here is the difference: (>>=) for State: ma >>= f = State $ \s0 -> let (a, s1) = runState ma s0 in runState (f a) s1 The "let" is a lazy pattern match; in particular, consider this code: runState (do put 0 put 1) 2 -> desugar runState (put 0 >> put 1) 2 The rest is lazy evaluation in action! -> apply >> runState (put 0 >>= \_ -> put 1) 2 -> apply >>= runState (State $ \s0 -> let (a, s1) = runState (put 0) s0 in runState (put 1) s1 ) 2 -> apply runState (\s0 -> let (a,s1) = runState (put 0) s0 in runState (put 1) s1 ) 2 -> beta reduce let s0 = 2 in let (a,s1) = runState (put 0) s0 in runState (put 1) s1 -> apply put let s0 = 2 in let (a,s1) = runState (put 0) s0 in runState (State $ \_ -> ((), 1)) s1 -> apply runState let s0 = 2 in let (a,s1) = runState (put 0) s0 in (\_ -> ((), 1)) s1 -> beta reduce let s0 = 2 in let (a,s1) = runState (put 0) s0 in ((), 1) -> garbage collect ((), 1) Note that at no point were s0, a, or s1 evaluated; so there was no need to evaluate the state at all! Furthermore, even if you replace (put 0) with a computation that loops and looks at the state at each point, the result is immediately a pair, so future computation can continue. Now lets contrast with IO: (>>=) for IO (taking out the "unboxed pairs" stuff which muddles the issue) ma >>= f = IO $ \s0 -> case (unIO ma s0) of (a, s1) -> unIO (f a) s1 (Note that this is the basically the same as Control.Monad.State.Strict) Consider main = do putStrLn "hello" putStrLn "world" We'll use this definition of putStrLn for simplicity's sake:
-- primitive, unsafe, side-effecting function. putStrLn# :: String -> ()
putStrLn :: String -> IO () putStrLn s = IO $ \w -> seq (putStrLn# s) ((), w)
So putStrLn is an IO action which takes a "world" (a dummy value that doesn't really exist) as input, and before it gives any output, forces the evaluation of a side-effecting primitive function via seq. It then returns a pair containing the result (), and the original "world" argument as the state. Desugar: main = (putStrLn "hello" >> putStrLn "world") Send to the runtime: unIO (putStrLn "hello" >> putStrLn "world") world# Now lets evaluate it. -> Apply >> unIO (putStrLn "hello" >>= \_ -> putStrLn "world") world# -> Apply >>= unIO (IO $ \w0 -> case unIO (putStrLn "hello") w0 of (a, w1) -> unIO ((\_ -> putStrLn "world") a) w1 -> Apply unIO and beta-reduce case unIO (putStrLn "hello") world# of (a, w1) -> unIO ((\_ -> putStrLn "world") a) w1 Note that the evaluation order is different here; since we have a case statement, we must force the evaluation of the first putStrLn to make sure it evaluates to a pair! -> Apply putStrLn case unIO (IO $ \w -> seq (putStrLn# "hello") ((), w)) world# of (a, w1) -> unIO ((\_ -> putStrLn "world") a) w1 -> apply unIO & beta-reduce case seq (putStrLn# "hello") ((), world#) of (a, w1) -> unIO ((\_ -> putStrLn "world") a) w1 -> seq evaluates putStrLn#, side effect happens here! case ((), world#) of (a, w1) -> unIO ((\_ -> putStrLn "world") a) w1 -> pattern match in case succeeds now let a = () w1 = world# in unIO ((\_ -> putStrLn "world") a) w1 -> beta reduce & garbage collect unIO (putStrLn "world") world# -> apply putStrLn unIO (IO $ \w -> seq (putStrLn# "world") ((), w)) world# -> apply unIO & beta reduce seq (putStrLn# "world") ((), world#) -> seq evaluates putStrLn#, side effect happens here! ((), world#) Now, you are probably wondering for the reason behind the use of "case" vs. "let". It's pretty simple; lets evaluate that last code using the lazy method like State. Everything is the same up to "apply
=", so start there:
unIO (putStrLn "hello" >>= \_ -> putStrLn "world") world# -> Apply >>= unIO (IO $ \w0 -> let (a, w1) = unIO (putStrLn "hello") w0 in unIO (putStrLn "world") w1 ) world# -> apply unIO and beta-reduce let (a, w1) = unIO (putStrLn "hello") world# in unIO (putStrLn "world") w1 -> apply putStrLn (the second one!) let (a, w1) = unIO (putStrLn "hello") world# in unIO (IO $ \w -> seq (putStrLn# "world") ((), w)) w1 -> apply unIO and beta-reduce let (a, w1) = unIO (putStrLn "hello") world# in seq (putStrLn# "world" w1) ((), w1) Now we call putStrLn# which causes a side effect. It ignores the "world" argument and just returns it unchanged, of course. We could also add extra machinery to the compiler to force it to treat the "world" argument as strictly, but you can see that using "lazy" really changes the order of evaluation, which ends up making the code much harder to optimize. -> seq evaluates putStrLn# (printing "world", oops!) let (a,w1) = unIO (putStrLn "hello" world#) in ((), w1) We need w1 here, so we have to force evaluation of the pair to extract it. -> apply putStrLn let (a,w1) = unIO (IO $ \w -> seq (putStrLn# "hello") ((), w)) world# in ((), w1) -> apply unIO & beta-reduce let (a,w1) = seq (putStrLn# "hello") ((), world#) in ((), w1) -> seq evaluates putStrLn#, printing "hello" let (a,w1) = ((), world#) in ((), w1) -> garbage-collect ((), world#) I've omitted some of the details, and this isn't exactly how it works. In particular, I believe GHC's primitive operations take the World# argument directly, so you can argue that this behavior wouldn't happen as long as that argument was considered "strict". But the "lazy" behavior makes the order of evaluation much harder to predict, which I think is considered to be bad for IO, which lives on the "imperative" side of the imperative/functional divide. In particular, unsafeInterleaveIO (and its friend getContents) would be even more difficult to use correctly if IO used a "lazy state" monad. It might be possible to build a "lazy-ify" monad transformer which would make this work. In particular, I think Oleg's LogicT transformer[1] does something of the sort, only applying side effects where they are required in order to get "the next result" in a nondeterministic computation. -- ryan [1] http://okmij.org/ftp/Computation/monads.html#LogicT

2008/12/31 Paolino
: I must ask why runWriterT k :: State s (a,[Int]) is working. Looks like I could runIO the same way I evalState there. In that case I wouldn't wait for the State s action to finish.
Thanks
Assuming you have Control.Monad.State.Lazy (which I think is the default), here is the difference: [...] There's a much simpler way of understanding why you must wait for an IO computation to finish before you can use the result. In IO you can
On Thu, 2009-01-01 at 02:17 -0800, Ryan Ingram wrote: throw exceptions (IOErrors), so you must wait until an IO computation is finished to know that there is any result at all.

On Thu, Jan 1, 2009 at 5:17 AM, Ryan Ingram
It might be possible to build a "lazy-ify" monad transformer which would make this work. In particular, I think Oleg's LogicT transformer[1] does something of the sort, only applying side effects where they are required in order to get "the next result" in a nondeterministic computation.
LogicT is continuation-based, so it's strict in the first argument to (>>=).
observeT $ undefined >>= \_ -> return ()
will throw an exception.
On the other hand, LogicT is non-strict in the second argument to
mplus if the transformed monad is non-strict in (>>=).
take 4 . runIdentity . observeAllT . msum $ map return [0..]
should return [0,1,2,3].
(My implementation does. I assume the LogicT on Hackage is the same.)
--
Dave Menendez

IO is not lazy; you never make it to "print". Consider this program:
k = f 0 where f n = do lift (print n) tell [n] f (n+1)
weird :: IO [Int] weird = do (_, ns) <- runWriterT k return (take 20 ns)
What should "weird" print? According to "k", it prints every Int from
0 up. Aside from the extra printing, it has the same behavior as your
writer.
For the result of a WriterT to be lazy readable, you need both the
monoid to be lazy readable, and the transformed monad to be lazy,
which IO isn't.
-- ryan
2008/12/31 Paolino
As someone suggested me, I can read the logs from Writer and WriterT as computation goes by, if the monoid for the Writer is lazy readable. This has been true until I tried to put the IO inside WriterT
{-# LANGUAGE FlexibleContexts #-} import Control.Monad.Writer
k :: (MonadWriter [Int] m) => m [Int]
k = let f x = tell [x] >> f (x + 1) in f 0
works :: [Int] works = snd $ runWriter k
hangs :: IO [Int] hangs = snd `liftM` runWriterT k
main = take 20 `liftM` hangs >>= print
The main hangs both interpreted and compiled on ghc 6.10.1.
The issue is not exposing with IO alone as
main = print "test" >> main
is a working program.
Thanks for explanations.
paolino
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

How do I read "IO is not lazy" ?
Is IO (>>=) forcing the evaluation of its arguments, causing the unwanted
neverending loop?
And, this happens even in (MonadTrans t => t IO) (>>=) ?
Thanks
paolino
2008/12/31 Ryan Ingram
IO is not lazy; you never make it to "print".
Consider this program:
k = f 0 where f n = do lift (print n) tell [n] f (n+1)
weird :: IO [Int] weird = do (_, ns) <- runWriterT k return (take 20 ns)
What should "weird" print? According to "k", it prints every Int from 0 up. Aside from the extra printing, it has the same behavior as your writer.
For the result of a WriterT to be lazy readable, you need both the monoid to be lazy readable, and the transformed monad to be lazy, which IO isn't.
-- ryan
2008/12/31 Paolino
: As someone suggested me, I can read the logs from Writer and WriterT as computation goes by, if the monoid for the Writer is lazy readable. This has been true until I tried to put the IO inside WriterT
{-# LANGUAGE FlexibleContexts #-} import Control.Monad.Writer
k :: (MonadWriter [Int] m) => m [Int]
k = let f x = tell [x] >> f (x + 1) in f 0
works :: [Int] works = snd $ runWriter k
hangs :: IO [Int] hangs = snd `liftM` runWriterT k
main = take 20 `liftM` hangs >>= print
The main hangs both interpreted and compiled on ghc 6.10.1.
The issue is not exposing with IO alone as
main = print "test" >> main
is a working program.
Thanks for explanations.
paolino
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I think I have a very similar problem to the currently discussed "WriterT [w] IO is not lazy in reading [w]". I want to defer IO actions, until they are needed, but they shall be executed in order. If I call unsafeInterleaveIO, they can be executed in any order. I understand that hGetContents does not defer the hGetChar operations but instead defers the call of the (:) constructors, thus preserving the order of the hGetChar calls. In the general case this is not so simple, since the result of a monadic block might not be a list and the result of particular actions might not be needed at all, e.g. (). If it is generally possible to use unsafeInterleaveIO such that it executes actions in the right order, wouldn't this allow the definition of a general lazy IO monad?

On 2009 Jan 1, at 16:44, Henning Thielemann wrote:
If it is generally possible to use unsafeInterleaveIO such that it executes actions in the right order, wouldn't this allow the definition of a general lazy IO monad?
I thought unsafeInterleaveIO and users of it (readFile, hGetContents) didn't guarantee the order of actions relative to independent IO actions (that is, those performed outside the unsafeInterleaveIO) and this was why it is generally disrecommended. For example the recurring situation where people try to readFile f >>= writeFile . someTransform and the writeFile fails with a "file locked" exception. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

On Thu, 1 Jan 2009, Brandon S. Allbery KF8NH wrote:
On 2009 Jan 1, at 16:44, Henning Thielemann wrote:
If it is generally possible to use unsafeInterleaveIO such that it executes actions in the right order, wouldn't this allow the definition of a general lazy IO monad?
I thought unsafeInterleaveIO and users of it (readFile, hGetContents) didn't guarantee the order of actions relative to independent IO actions (that is, those performed outside the unsafeInterleaveIO) and this was why it is generally disrecommended. For example the recurring situation where people try to readFile f >>= writeFile . someTransform and the writeFile fails with a "file locked" exception.
Sure, it's dangerous. But for what I want to do, this situation cannot occur. I can come up with a simple example which might be generalized. It simulates what hGetContents does. liftLazy2 :: (a -> b -> c) -> IO a -> IO b -> IO c liftLazy2 f x y = fmap (\ ~(xr, ~(yr,())) -> f xr yr) $ unsafeInterleaveIO $ liftM2 (,) x $ unsafeInterleaveIO $ liftM2 (,) y $ return () test0, test1 :: IO String test0 = liftLazy2 (const) getLine getLine test1 = liftLazy2 (flip const) getLine getLine test0 only requests the first line, test1 expects two lines as user input. However, with liftLazy2 we have only Applicative functionality, not Monad, and it is not composable. For example: fmap (\((x,y),z) -> z) $ liftLazy2A (,) (liftLazy2A (,) getLine getLine) getLine This requests only one line, but should three ones. The reason is that the first two getLines are defered even until the last one. Thus, it is not enough that liftLazy2 returns (IO c). Instead it must return (IO (c,(a,(b,())))) and these pair emulated lists must somehow be combined in order to preserve the order of execution. This looks somehow like a writer monad transformer.

On Sat, 3 Jan 2009, Henning Thielemann wrote:
On Thu, 1 Jan 2009, Brandon S. Allbery KF8NH wrote:
On 2009 Jan 1, at 16:44, Henning Thielemann wrote:
If it is generally possible to use unsafeInterleaveIO such that it executes actions in the right order, wouldn't this allow the definition of a general lazy IO monad?
I thought unsafeInterleaveIO and users of it (readFile, hGetContents) didn't guarantee the order of actions relative to independent IO actions (that is, those performed outside the unsafeInterleaveIO) and this was why it is generally disrecommended. For example the recurring situation where people try to readFile f >>= writeFile . someTransform and the writeFile fails with a "file locked" exception.
Sure, it's dangerous. But for what I want to do, this situation cannot occur. I can come up with a simple example which might be generalized. It simulates what hGetContents does.
liftLazy2 :: (a -> b -> c) -> IO a -> IO b -> IO c liftLazy2 f x y = fmap (\ ~(xr, ~(yr,())) -> f xr yr) $ unsafeInterleaveIO $ liftM2 (,) x $ unsafeInterleaveIO $ liftM2 (,) y $ return ()
I think I now have general Applicative functionality: apply :: (a -> b, ()) -> (a,()) -> (b,()) apply (f,fs) a = let (a0,as) = case fs of () -> a in (f a0, as) lazyIO :: IO a -> IO (a,()) lazyIO = unsafeInterleaveIO . fmap (\x -> (x,())) liftLazy2 :: (a -> b -> c) -> IO a -> IO b -> IO c liftLazy2 f x y = liftM2 (\xr yr -> fst $ (f,()) `apply` xr `apply` yr) (lazyIO x) (lazyIO y) The () is used to enforce the order of evaluation.

On Sat, 3 Jan 2009, Henning Thielemann wrote:
I think I now have general Applicative functionality ...
I hope the following is a proper Monad implementation. In contrast to Applicative a Writer for sequencing actions does no longer work, instead I need a State monad. newtype LazyIO a = LazyIO {runLazyIO :: StateT RunAll IO a} data RunAll = RunAll deriving Show instance Monad LazyIO where return x = LazyIO $ return x x >>= f = LazyIO $ mapStateT unsafeInterleaveIO . runLazyIO . f =<< mapStateT unsafeInterleaveIO (runLazyIO x) instance MonadIO LazyIO where liftIO m = LazyIO $ StateT $ \RunAll -> fmap (\x->(x,RunAll)) m evalLazyIO :: LazyIO a -> IO a evalLazyIO = flip evalStateT RunAll . runLazyIO I'll write some tests and upload it to Hackage. Thank you for being a patient audience. ;-)

Henning Thielemann
If it is generally possible to use unsafeInterleaveIO such that it executes actions in the right order, wouldn't this allow the definition of a general lazy IO monad?
The question is what "right order" means. Let B1..Bn be some arbitrary IO-Actions. Let A1..An be some arbitrary IO Actions passed to unsafeInterleaveIO You're guaranteed that a) Bk+1 is executed after Bk b) Ak+1 is executed after Ak , all by virtue of the IO Monad. However, usage of unsafeInterleaveIO means that you aren't guaranteed that A1..An happens _exactly_ between any pair of Bk and Bk+1: The total ordering of actions is circumvented. Semantically, this is equivalent to sparking a thread on a uniprocessor, and equivalent to sparking a thread on a multiprocessor for all but the rarest combinations of IO actions. There are no lazy monads. Monads imply explicit sequencing... writing kiss girl =><= speakTo girl , denoting "either (fist kiss the girl, then pass the result of that to speakTo girl) or (first speak to the girl, then pass the result of that to kiss girl) would, OTOH, certainly makes sense and certainly (well, depending on girl and setting) is undeterministic in both execution order and result. The question thus becomes: "Does arbitrary ordering of actions result in the same (in the id sense) result, and do I care more about the aggregate result than its ordering, or do I only care about ordering of actions for a certain definition of 'same result'?" Implementation of such a beast is left to the semantically inclined reader ;) In the meantime, I'm happy to just carelessly use unsafe*IO. -- (c) this sig last receiving data processing entity. Inspect headers for copyright history. All rights reserved. Copying, hiring, renting, performance and/or quoting of this signature prohibited.

On Fri, 2 Jan 2009, Achim Schneider wrote:
Henning Thielemann
wrote: If it is generally possible to use unsafeInterleaveIO such that it executes actions in the right order, wouldn't this allow the definition of a general lazy IO monad?
The question is what "right order" means.
Let B1..Bn be some arbitrary IO-Actions. Let A1..An be some arbitrary IO Actions passed to unsafeInterleaveIO
You're guaranteed that a) Bk+1 is executed after Bk b) Ak+1 is executed after Ak
, all by virtue of the IO Monad.
If all Ak's are defered using individual unsafeInterleaveIO's then it is not guaranteed that A[k+1] is executed after A[k]. That's my problem. Check: Prelude> fmap snd $ Monad.liftM2 (,) (unsafeInterleaveIO getLine) (unsafeInterleaveIO getLine) If unsafely interleaved actions would be executed in order, then this would first ask you for the first pair member, then for the second one, then echo the second one. Actually it asks only for the second one and prints it.

Henning Thielemann
On Fri, 2 Jan 2009, Achim Schneider wrote:
Henning Thielemann
wrote: If it is generally possible to use unsafeInterleaveIO such that it executes actions in the right order, wouldn't this allow the definition of a general lazy IO monad?
The question is what "right order" means.
Let B1..Bn be some arbitrary IO-Actions. Let A1..An be some arbitrary IO Actions passed to unsafeInterleaveIO
You're guaranteed that a) Bk+1 is executed after Bk b) Ak+1 is executed after Ak
, all by virtue of the IO Monad.
If all Ak's are defered using individual unsafeInterleaveIO's then it is not guaranteed that A[k+1] is executed after A[k]. That's my problem.
Check: Prelude> fmap snd $ Monad.liftM2 (,) (unsafeInterleaveIO getLine) Prelude> (unsafeInterleaveIO getLine)
If unsafely interleaved actions would be executed in order, then this would first ask you for the first pair member, then for the second one, then echo the second one. Actually it asks only for the second one and prints it.
module Main where import System.IO.Unsafe chooseAct :: String -> IO (IO ()) chooseAct s = do putStrLn $ s ++ "?" l <- getLine if (l == s) then return $ putStrLn $ "w00t! a " ++ s else return $ putStrLn "bah" getActs :: IO [IO ()] getActs = mapM chooseAct ["foo", "bar", "baz"] main0 = unsafeInterleaveIO getActs >>= unsafeInterleaveIO . sequence_ main1 = unsafeInterleaveIO getActs >>= sequence_ main = main0 >> main1 There you've got the ordering. It's quite easy to write a haskell program that reduces itself to main = return (), though. -- (c) this sig last receiving data processing entity. Inspect headers for copyright history. All rights reserved. Copying, hiring, renting, performance and/or quoting of this signature prohibited.

Achim Schneider
[...] actually, even better:
main = do acts <- unsafeInterleaveIO getActs putStrLn "dumdidum" sequence_ acts , which, at least on my machine, prints dumdidum before asking for foo. -- (c) this sig last receiving data processing entity. Inspect headers for copyright history. All rights reserved. Copying, hiring, renting, performance and/or quoting of this signature prohibited.

On Thu, Jan 1, 2009 at 7:39 PM, Achim Schneider
There are no lazy monads. Monads imply explicit sequencing...
Huh? How are you defining "lazy monad"?
--
Dave Menendez

On 2009 Jan 1, at 20:08, David Menendez wrote:
On Thu, Jan 1, 2009 at 7:39 PM, Achim Schneider
wrote: There are no lazy monads. Monads imply explicit sequencing...
Huh? How are you defining "lazy monad"?
We've had this discussion before; somewhere in the archives is an example of a State monad doing things in data-driven order instead of the apparently "explicit" monadic sequencing. Monads don't insure sequencing unless designed to do so (as, for example, IO). -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

"Brandon S. Allbery KF8NH"
On 2009 Jan 1, at 20:08, David Menendez wrote:
On Thu, Jan 1, 2009 at 7:39 PM, Achim Schneider
wrote: There are no lazy monads. Monads imply explicit sequencing...
Huh? How are you defining "lazy monad"?
We've had this discussion before; somewhere in the archives is an example of a State monad doing things in data-driven order instead of the apparently "explicit" monadic sequencing. Monads don't insure sequencing unless designed to do so (as, for example, IO).
The more I try to put stuff into words, the more I part from lambda calculus into the regions of syntactical pitfalls. Therefore, I'm just going to shut up. -- (c) this sig last receiving data processing entity. Inspect headers for copyright history. All rights reserved. Copying, hiring, renting, performance and/or quoting of this signature prohibited.

On Thu, Jan 1, 2009 at 8:29 PM, Brandon S. Allbery KF8NH
On 2009 Jan 1, at 20:08, David Menendez wrote:
On Thu, Jan 1, 2009 at 7:39 PM, Achim Schneider
wrote: There are no lazy monads. Monads imply explicit sequencing...
Huh? How are you defining "lazy monad"?
We've had this discussion before; somewhere in the archives is an example of a State monad doing things in data-driven order instead of the apparently "explicit" monadic sequencing. Monads don't insure sequencing unless designed to do so (as, for example, IO).
Certainly. I asked because Achim might have been making a point about
about call-by-need versus call-by-value, or something.
--
Dave Menendez

"David Menendez"
On Thu, Jan 1, 2009 at 8:29 PM, Brandon S. Allbery KF8NH
wrote: On 2009 Jan 1, at 20:08, David Menendez wrote:
On Thu, Jan 1, 2009 at 7:39 PM, Achim Schneider
wrote: There are no lazy monads. Monads imply explicit sequencing...
Huh? How are you defining "lazy monad"?
We've had this discussion before; somewhere in the archives is an example of a State monad doing things in data-driven order instead of the apparently "explicit" monadic sequencing. Monads don't insure sequencing unless designed to do so (as, for example, IO).
Certainly. I asked because Achim might have been making a point about about call-by-need versus call-by-value, or something.
Nah, I was speculating about (possibly better) ways to specify dependencies of side-effects. Ways, that is, that enable the computer to directly implement your perception of priorities like importance of ordering vs. importance of results. -- (c) this sig last receiving data processing entity. Inspect headers for copyright history. All rights reserved. Copying, hiring, renting, performance and/or quoting of this signature prohibited.

On Fri, 2 Jan 2009, Achim Schneider wrote:
There are no lazy monads. Monads imply explicit sequencing... writing
I think this is an extremely bad thing to say and is a source of misunderstanding about monads and evaluation. Most monads _are_ lazy, and it is important to understand that when trying to understand the run-time properties of your monadic code. Monads sequence effects, but evaluation is an almost orthogonal issue. Here is a recent thread where I talk about laziness: http://www.reddit.com/r/haskell/comments/7itbi/mapm_mapm_and_monadic_stateme... (for the short short story, simply try out
take 10 $ execWriter (sequence_ (repeat (tell "x"))) )
Furthermore, the code in my article on recursive do from The.Monad.Reader issue #6 http://www.haskell.org/sitewiki/images/1/14/TMR-Issue6.pdf requires the monads to be lazy in order to tie the knot. -- Russell O'Connor http://r6.ca/ ``All talk about `theft,''' the general counsel of the American Graphophone Company wrote, ``is the merest claptrap, for there exists no property in ideas musical, literary or artistic, except as defined by statute.''
participants (9)
-
Achim Schneider
-
Brandon S. Allbery KF8NH
-
David Menendez
-
Derek Elkins
-
Henning Thielemann
-
Henning Thielemann
-
Paolino
-
roconnor@theorem.ca
-
Ryan Ingram