<!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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; infoPath :: FilePath<br>
&nbsp;&nbsp;&nbsp; , infoPerms :: Maybe Permissions<br>
<br>
&nbsp;&nbsp;&nbsp; , infoSize :: Maybe Integer<br>
&nbsp;&nbsp;&nbsp; , infoModTime :: Maybe ClockTime<br>
&nbsp;&nbsp;&nbsp; } deriving (Eq, Ord, Show)<br>
<br>
getInfo :: FilePath -&gt; IO Info</tt></blockquote>
<blockquote type="cite" cite><tt>-- file: ch09/ControlledVisit.hs<br>
<br>
traverse order path = do<br>
&nbsp;&nbsp;&nbsp; names &lt;- getUsefulContents
path</tt></blockquote>
<blockquote type="cite" cite><tt>&nbsp;&nbsp;&nbsp; contents &lt;-
mapM getInfo (path : map (path &lt;/&gt;) names)<br>
&nbsp;&nbsp;&nbsp; liftM concat $ forM (order contents) $ \info -&gt;
do<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if isDirectory info &amp;&amp; infoPath
info /= path<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; then traverse order
(infoPath info)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else return [info]</tt><br>
<tt></tt></blockquote>
<blockquote type="cite" cite><tt>getUsefulContents :: FilePath -&gt;
IO [String]<br>
getUsefulContents path = do<br>
&nbsp;&nbsp;&nbsp; names &lt;- getDirectoryContents path<br>
&nbsp;&nbsp;&nbsp; return (filter (`notElem` [&quot;.&quot;,
&quot;..&quot;]) names)<br>
<br>
<br>
isDirectory :: Info -&gt; 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 &quot;order contents&quot;
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>
&quot;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&quot;</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 &quot;order
contents&quot;,<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.&nbsp; 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.&nbsp; But this kind of &quot;lazy I/O&quot; is not at play
here.</div>
<div><br></div>
<div>I/O is a special monad.&nbsp; Its semantics are that I/O actions
are performed in sequence, regardless of demands (or lack thereof) on
the actions' results.&nbsp; (This is so that real-world side effects
occur in determinstic order.)&nbsp; 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.&nbsp; `getUsefulContents` uses
`getDirectoryContents`, which computes its result list completely
before returning it.&nbsp; (The documentation doesn't say that
explicitly.&nbsp; It is implied because it doesn't say that the result
is returned lazily.)&nbsp; So both `names` and `contents` could be
very large, as the authors note.</div>
<div><br></div>
<div>Some describe these semantics by saying &quot;the I/O monad is
strict&quot;, 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>