The fate of S, K and I

Antonio Eduardo Costa Pereira costa@ufu.br
Mon, 22 Feb 1999 20:35:08 -0300


matthews@math.uga.edu wrote:
> 
> The suggestion was that since Haskell I/O did not support
> multiple environments it was somehow "unsafe". I have quoted all these
> things because I am not sure what is being talked about here. I was
> wondering if anyone (hopefully Pascal?) could post an article/example/
> reference outlining the issues.


Dear graham (I see that you have a lower case name, like e.m. cummings).
After reading Pascal's article and your posting, I decided to compare
Clean with Haskell, as far as I/O goes. I started implementing a simple
database in Clean. Although not familiar with BTREES, I implemented it
in a couple of hours (most of the time was spent studying the
algorithms). Clean compiler catched every single mistake I did
during the process. Besides this, the environment passing style
was suprisingly terse and clear. I will post the whole program in
my home page soon. In case you don't know, the address is:...

	http://www.deene.ufu.br/clean/clean1.html

Since you like French, like myself, I will explain the programs 
in French.  To make a long story short, most of I/O mistakes (in
my opinion, of course) comes from: (1) A function updating a file
with the wrong file pointer (2) A function updating a file with
a wrong handle. Since Clean prevents two different functions from
updating the same environment, the compiler easily catches these 
nasty errors. Now, for the example.

My Haskell compiler goes happily through the program below
without a single warning:

import IO
main=
	do
		fromHandle <- openFile "c:\\lixo.txt"  ReadMode
		toHandle <- openFile "c:\\xico.txt" WriteMode
		contents <- hGetContents fromHandle
		hPutStr toHandle contents
		hClose toHandle
		hPutStr toHandle "Rosinha"
		hClose toHandle
		putStr "Done"

Of course, I get a runtime error whenever I try to execute the beast,
as Pascal foretold. On the other hand, Clean compiler refuses the
equivalent program:

Start world
#	(ok, fromHandle, world)= fopen "c:\\lixo.txt" FReadText world
;	(ok, toHandle, world)= fopen "c:\\xico.txt" FWriteText world
;	(contents, fromHandle)= freads fromHandle 1000
;	toHandle = fwrites contents toHandle
;	(ok, world)= fclose toHandle world
;	toHandle = fwrites "Rosinha" toHandle
;	(ok, world)= fclose toHandle world
= (world, "Done");

The error message is:

Type error [closit.icl,10,Start]: "argument 2 of fwrites" * attribute
required but not offered at the indicated position: ^ File

Of course, the programs of the example are obviously wrong. However,
there are situations where the mistake is not so obvious, and Clean
refusal to compile the wrong program is quite helpful. Consider this
small excerpt of the simple database manager that I wrote:

bInsert (elem, env) i
#	(env1, page)= getPage env i
|	isLeaf page= Split (env, page) i elem
|	otherwise= Down mkIns elem page env;

I did commit this mistake. I should have used the environment 
updated by getPage (i.e. env1). Instead of this, I used env.
The compiler pointed out the mistake and a few seconds later
the program was running.