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