<html>
<body>
At 05:01 PM 7/9/2005, Wolfgang Jeltsch wrote:<br>
<blockquote type=cite class=cite cite="">[..]<br>
Hello,<br><br>
the idea is to have different monads for I/O on different
resources.&nbsp; A simple <br>
example is to have the two monads WorldIO and FileIO and a type
FileIOHandle.&nbsp; <br>
A file is a part of the world.&nbsp; You have the following
functions:<br><br>
&nbsp;&nbsp;&nbsp; readChar :: FileIO Char<br>
&nbsp;&nbsp;&nbsp; writeChar :: Char -&gt; FileIO ()<br>
&nbsp;&nbsp;&nbsp; runFileIO :: FilePath -&gt; FileIO a -&gt; WorldIO (a,
FileIOHandle)<br>
&nbsp;&nbsp;&nbsp; finishFileIO :: FileIOHandle -&gt; WorldIO 
()<br><br>
readChar and writeChar should be self-explanatory.&nbsp; At first,
runFileIO does <br>
nothing instead of opening the file and returning the result.&nbsp;
Whenever parts <br>
of the first component of the result pair are evaluated, as much readChar
and <br>
writeChar actions of the file I/O action are executed as are needed to
<br>
produce the desired parts of the result.&nbsp; finishFileIO executes the
remainder <br>
of the file I/O and closes the file afterwards.</blockquote><br>
I am always interested in functional I/O solutions that adopt the
&quot;world-as-value&quot; paradigm (or the more verbose &quot;explicit
multiple environment passing&quot; paradigm) that has been exploited in
Clean's file I/O system and GUI library. Your idea sounds interesting,
but your explanation above of runFileIO and finishFileIO raises a few
questions:<br><br>
(1) Suppose you have a file with content &quot;abcde&quot; at path p.
What does the following program fragment yield?
<dl>
<dd><tt>do
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (r1,h1) &lt;- runFileIO p
readEntireFile
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (r2,h2) &lt;- runFileIO p
readEntireFile
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return hd r1 : hd 
r2</tt>
</dl>where readEntireFile reads the entire file and returns it as a
string. I can imagine several results: [a,a], [a,b], [a,_|_], [_|_,_|_],
_|_.<br><br>
(2) Can a writer interfere with a reader? Let writeFile :: Integer -&gt;
Char -&gt; FileIO () write n times a given char to a file. What is then
the result of:
<dl>
<dd><tt>do
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  (r1,h1) &lt;- runFileIO p
readEntireFile
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (r2,h2) &lt;- runFileIO p
(writeFile 5 'X')
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (r2,r1)</tt>
</dl>Does it yield ((),&quot;abcde&quot;), ((),&quot;XXXXX&quot;),
(_|_,&quot;abcde&quot;), or _|_? What is the result when (r1,r2) is
returned instead of (r2,r1)?<br><br>
(3) One of the advantages of an explicit environment passing scheme is
that you get true functional behaviour of programs. As an example, in
Clean you can write a function that tests the content of a file, and if
successfull proceeds with the remainder, and otherwise with its argument
file. (Clean code ahead):
<dl>
<dd><tt>parseInt :: Int File -&gt; (Int,File)
<dd>parseInt n file
<dd>&nbsp;&nbsp;&nbsp; | ok &amp;&amp; isDigit c = parseInt (n*10+d)
file1
<dd>&nbsp;&nbsp;&nbsp; | otherwise&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; =
(n,file)
<dd>where (ok,c,file1)&nbsp;&nbsp;&nbsp; = sfreadc file
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
= toInt c - toInt '0'</tt>
</dl>Does your scheme allow such kind of behavior?<br><br>
<blockquote type=cite class=cite cite="">An extended version of this
approach shall also handle situations like pure <br>
reading of files where not all read operations have to be carried out if
they <br>
are not needed to produce the desired result.&nbsp; In this case,
finishFileIO <br>
would just close the file without previously executing the remainder of
the <br>
file I/O action.&nbsp; The problem is that it cannot be assured that as
yet <br>
unevaluated parts of the result aren't evaluated after exeuction of 
<br>
finishFileIO.&nbsp; Therefore, if evaluation after finishing demands the
execution <br>
of read operations these operations shall not actually be executed but
<br>
instead _|_ shall be returned.</blockquote><br>
This scheme forces the programmer to carefully plan calls to
finishFileIO. Let's assume that the readEntireFile is a pure reader of
files, then the program fragment:
<dl>
<dd><tt>do
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (r1,h1) &lt;- runFileIO p
readEntireFile
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finishFileIO h1
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... computations that use
r1 ...</tt>
</dl>always use _|_ for r1. It is not always the case that
<dl>
<dd><tt>do
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (r1,h1) &lt;- runFileIO p
readEntireFile
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... computations that use
r1 ...
<dd>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finishFileIO h1</tt>
</dl>solves the problem, in particular when the computations that use r1
are pure functions. You'd have to &quot;connect&quot; r1 to the WorldIO
monad before doing finishFileIO on h1.<br><br>
How can you tell a function is a pure reader?<br><br>
<blockquote type=cite class=cite cite="">I also plan to provide a general
framework for working on parts of the state <br>
interleaved with working on the remainder of the state.&nbsp; The
framework shall <br>
be hierarchical in the sense that you cannot just work on parts of the
world <br>
but also on parts of parts of the world and so on.&nbsp; It will probably
use <br>
multi-parameter classes to describe which thing is part of which other
thing.<br><br>
When my diploma thesis and the corresponding talk are finished (which
will <br>
probably at the end of September), I may post a more detailed description
on <br>
this list and also provide some code.</blockquote><br>
Good luck with your thesis. I'd like to see the final result.<br><br>
Regards,<br>
Peter Achten<br>
</body>
<br>
</html>