
I'm trying to grok Haskell's laziness. In this example, why does the seq not force youTyped to wait for s to be fully evaluated, before returning a result to putStrLn? -------------------- import System.IO (hSetBuffering,stdin,BufferMode(..)) youTyped :: String -> String youTyped s = s `seq` "you typed: " ++ s main = do hSetBuffering stdin NoBuffering s <- getContents let l = map youTyped $ lines $ takeWhile ( /= '\04' ) s mapM_ putStrLn ("Start Typing (Ctrl-D to exit):":l) -------------------- The output looks like: -------------------- $ runhaskell seqLazy.hs Start Typing (Ctrl-D to exit): Hyou typed: Heelllloo wwoorrlldd fyou typed: faaiill ^D -------------------- Changing seq, to deepseq does the trick though. -------------------- import System.IO (hSetBuffering,stdin,BufferMode(..)) import Control.DeepSeq youTyped :: String -> String youTyped s = s `deepseq` "you typed: " ++ s main = do hSetBuffering stdin NoBuffering s <- getContents let l = map youTyped $ lines $ takeWhile ( /= '\04' ) s mapM_ putStrLn ("Start Typing (Ctrl-D to exit):":l) -------------------- Output: $ runhaskell deepSeqLazy.hs Start Typing (Ctrl-D to exit): Hello world you typed: Hello world success you typed: success ^D When does it make sense to use seq then?

seq forces the term into weak-head normal form. Basically just enough to tell whether the list is `[]` or not. It's the same kind of evaluation that would happen if you pattern matched on the constructor. Only one Char needs to be read in order to make that determination. Sometimes this is desirable, but other times you want to traverse the whole structure and make sure everything is forced. The confusion is made much worse because you're using lazy IO. The `takeWhile (/= '\04')` is redundant here, the ^D never ends up in that string. Most cases where you use `seq` rather than `deepseq` are because you know that the substructure is already evaluated, or there is no need to evaluate it, and it may be very inefficient to do that redundant work. See also: * http://chimera.labs.oreilly.com/books/1230000000929/ch02.html#sec_par-eval-w... * https://hackhands.com/lazy-evaluation-works-haskell/ On Tue, Jul 21, 2015 at 7:29 PM, Ryan Warner < ryan.warner.mn+haskell@gmail.com> wrote:
I'm trying to grok Haskell's laziness. In this example, why does the seq not force youTyped to wait for s to be fully evaluated, before returning a result to putStrLn?
-------------------- import System.IO (hSetBuffering,stdin,BufferMode(..))
youTyped :: String -> String youTyped s = s `seq` "you typed: " ++ s
main = do hSetBuffering stdin NoBuffering s <- getContents let l = map youTyped $ lines $ takeWhile ( /= '\04' ) s mapM_ putStrLn ("Start Typing (Ctrl-D to exit):":l) --------------------
The output looks like:
--------------------
$ runhaskell seqLazy.hs
Start Typing (Ctrl-D to exit):
Hyou typed: Heelllloo wwoorrlldd
fyou typed: faaiill
^D --------------------
Changing seq, to deepseq does the trick though.
-------------------- import System.IO (hSetBuffering,stdin,BufferMode(..)) import Control.DeepSeq
youTyped :: String -> String youTyped s = s `deepseq` "you typed: " ++ s
main = do hSetBuffering stdin NoBuffering s <- getContents let l = map youTyped $ lines $ takeWhile ( /= '\04' ) s mapM_ putStrLn ("Start Typing (Ctrl-D to exit):":l) --------------------
Output:
$ runhaskell deepSeqLazy.hs
Start Typing (Ctrl-D to exit):
Hello world
you typed: Hello world
success
you typed: success
^D
When does it make sense to use seq then?
_______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
participants (2)
-
Bob Ippolito
-
Ryan Warner