<!doctype html public "-//W3C//DTD W3 HTML//EN">
<html><head><style type="text/css"><!--
blockquote, dl, ul, ol, li { padding-top: 0 ; padding-bottom: 0 }
--></style><title>Re: [Haskell-beginners] Question on monads and
laziness</title></head><body>
<div>At 9:23 AM +0530 7/26/09, Lakshmi Narasimhan Vaikuntam
wrote:</div>
<blockquote type="cite" cite>Hello<br>
I am studying Real World Haskell chapter 9. Here is a snippet of
code<br>
</blockquote>
<blockquote type="cite" cite><tt>data Info = Info {<br>
infoPath :: FilePath<br>
, infoPerms :: Maybe Permissions<br>
<br>
, infoSize :: Maybe Integer<br>
, infoModTime :: Maybe ClockTime<br>
} deriving (Eq, Ord, Show)<br>
<br>
getInfo :: FilePath -> IO Info</tt></blockquote>
<blockquote type="cite" cite><tt>-- file: ch09/ControlledVisit.hs<br>
<br>
traverse order path = do<br>
names <- getUsefulContents
path</tt></blockquote>
<blockquote type="cite" cite><tt> contents <-
mapM getInfo (path : map (path </>) names)<br>
liftM concat $ forM (order contents) $ \info ->
do<br>
if isDirectory info && infoPath
info /= path<br>
<br>
then traverse order
(infoPath info)<br>
else return [info]</tt><br>
<tt></tt></blockquote>
<blockquote type="cite" cite><tt>getUsefulContents :: FilePath ->
IO [String]<br>
getUsefulContents path = do<br>
names <- getDirectoryContents path<br>
return (filter (`notElem` [".",
".."]) names)<br>
<br>
<br>
isDirectory :: Info -> Bool<br>
isDirectory = maybe False searchable . infoPerms</tt></blockquote>
<blockquote type="cite" cite>When I read about IO in the previous
chapter, I learnt that reading a file can be done lazily.<br>
Here my doubt is that whether the expression "order contents"
would generate a list of directory contents (held in memory) for use
in forM construct. Because in a subsequent para, I find this line.<br>
<br>
"If we are traversing a directory containing 100,000 files of
which we care about three, we'll allocate a 100,000-element list
before we have a chance to trim it down to the three we really
want"</blockquote>
<blockquote type="cite" cite><tt><br>
<br>
Wouldn't laziness ensure that in the traverse function, when iterating
over directory contents using the list generated by "order
contents",<br>
it will generate just one element at a time and then free the memory
for that entry immediately since we are not using the referencing
list<br>
<br>
anymore in the rest of the function.<br>
<br>
Not sure whether I have understood the concept of laziness w.r.t
monads correctly. Please clarify my doubts with regard to the code
snippet.<br>
<br>
Thanks for your time.</tt></blockquote>
<blockquote type="cite" cite>--<br>
Regards</blockquote>
<blockquote type="cite" cite>Lakshmi Narasimhan T V</blockquote>
<div><br></div>
<div>These issues are a bit subtle.</div>
<div><br></div>
<div>Yes, a file can be read lazily. What this means is that
there are I/O actions (readFile and getContents, for example) which
produce lazy strings, for which the underlying read operations are
done as needed as the successive characters of the strings are
demanded. But this kind of "lazy I/O" is not at play
here.</div>
<div><br></div>
<div>I/O is a special monad. Its semantics are that I/O actions
are performed in sequence, regardless of demands (or lack thereof) on
the actions' results. (This is so that real-world side effects
occur in determinstic order.) And the I/O actions themselves
determine how much computation they do before offering their
results.</div>
<div><br></div>
<div>In the code you cited, `traverse` calls `getUsefulContents` to
generate a list of names. `getUsefulContents` uses
`getDirectoryContents`, which computes its result list completely
before returning it. (The documentation doesn't say that
explicitly. It is implied because it doesn't say that the result
is returned lazily.) So both `names` and `contents` could be
very large, as the authors note.</div>
<div><br></div>
<div>Some describe these semantics by saying "the I/O monad is
strict", but I don't think that's a precise statement, because
strictness is a property of a function (and its arguments), not of a
monad (at least as far as I understand).</div>
<div><br></div>
<div>I hope this helps.</div>
<div><br></div>
<div>Dean</div>
</body>
</html>