[clean-list] Advice on style, please
alanh@dcs.kcl.ac.uk
alanh@dcs.kcl.ac.uk
Sun, 16 Dec 2001 22:59:16 +0000 (GMT)
An appeal for guidance on style:
I have to introduce a class of 2nd year undergraduates to functional
programming. This is actually just one part of an introductory course on
operational semantics, but the decree is that I should teach the
semantics of imperative and functional and "logic" styles of programming,
and the class have so far only seen Java.
I want to give the class samples of code in all three styles.
The chosen examples are
the "Hello World!" program
the echo program
the copy program.
All should be robustly written, with adequate error messages.
Below is my first working version of the copy program in Clean.
Below that is a working version of the copy program in C.
The problem is that the C version appears much simpler and more economical.
I don't like this.
Functional programming is supposed to make programming simpler.
How can this version be improved?
I don't want to use the "#" notation, as that obscures the declarative
nature of the language.
One problem is the need to supply seemingly real files as values when
the program has already detected an error. The type system demands it.
It would be nice if there were a "null file" which could act as a
place holder, where the code below uses silly calls of the form
fopen "" FReadText w1
Any suggestions?
Regards
Alan Hutchinson
Dept. of Computer Science
King's College London
--------------------------------------------------------------------------
module copy
import StdEnv
import ArgEnv
Start :: *World -> *World
Start w0 = w6
where
(console1, w1) = stdio w0
argv = getCommandLine
argc = size argv
(console2, (fiOK, fi0, w2)) = state2
where
state2
| argc <> 3 = (console1 <<< "Usage:\ncopy <input file> <output file>\n",
fopen "" FReadText w1)
| otherwise = (console1, fopen argv.[1] FReadText w1)
(console3, (foOK, fo0, w3)) = state3
where
state3
| argc <> 3 = (console2, fopen "" FWriteText w2)
| not fiOK = (console2 <<< ("Can't open file " +++ argv.[1] +++ "\n"),
fopen "" FWriteText w2)
| otherwise = (console2, fopen argv.[2] FWriteText w2)
(console4, (ccOK, fi1, fo1)) = state4
where
state4
| not fiOK = (console3, (False, fi0, fo0))
| not foOK = (console3 <<< ("Can't open file " +++ argv.[2] +++ "\n"),
(False, fi0, fo0))
| otherwise = (console3, cc (fi0, fo0))
console5
| not foOK = console4
| not ccOK = console4 <<< "failed.\n"
| otherwise = console4
w4 = snd (fclose console5 w3)
w5 = snd (fclose fi1 w4)
w6 = snd (fclose fo1 w5)
cc :: (*File, *File) -> (Bool, *File, *File)
cc (fi0,fo0)
| atEnd = (True, fia, fo0)
| not ok = (False, fib, fo0)
| otherwise = cc (fib, fwritec c fo0)
where
(atEnd, fia) = fend fi0
(ok, c, fib) = freadc fia
--------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
main(int argc, char *argv[]) {
char c;
FILE *iFile, *oFile;
if (argc != 3) {
fprintf(stderr, "Usage:\ncopy <fromFile> <toFile>\n");
exit(1);
}
iFile = fopen(argv[1],"r");
if (iFile <= 0) {
printf("Cannot open input file %s\n", argv[1]);
exit(1);
}
oFile = fopen(argv[2],"w");
if (oFile <= 0) {
printf("Cannot open output file %s\n", argv[2]);
exit(1);
}
c = getc(iFile);
while (c != EOF) {
putc(c,oFile);
c = getc(iFile);
}
}