Elements of ML Programming, 2nd Edition (ML97)

Solutions for Chapter 4

Solutions for Section 4.1

Solutions for Section 4.2

Solutions for Section 4.3

Solutions for Section 4.1

Exercise 4.1.1

There is no type error. The value returned by the expression on line (1) of Fig. 4.3 is whatever printList returns on the tail of the given list. Thus, an easy induction on the length of the list shows that printList always returns 0. Another way to look at it is that the 0 in the new line (1) is the only concrete value ever produced by printList.

Exercise 4.1.3

fun xPrint1(0,s) = print(s)
|   xPrint1(n,s) = xPrint1(n-1, s^s);

fun xPrint(n) = (xPrint1(n,"X"),
                 print("\n")
                );
Notice that xPrint1 counts down in its first argument, as it doubles the length of its second argument. Thus, when started as in the third line, with first argument n and a second argument consisting of one X, by the time the first argument is down to 0, the length of the second argument is 2^n. That is the string that gets printed at line 1.

Return to Top

Solutions for Section 4.2

Exercise 4.2.1(a)

val IN = openIn("zap")

Technically, we are not required to retain the returned instream. However, if we do not bind it to some identifier, such as IN here, the token representing the instream is lost forever.

Exercise 4.2.1(b)

     closeIn(in1);
This and subsequent solutions assume that structure TextIO is already open.

Exercise 4.2.1(d)

     val newLine = inputLine(in3);

Exercise 4.2.1(g)

     fun howMany1(infile,i) =
         if not (canInput(infile,i+1)) then i
         else howMany(infile,i+1);

     fun howMany(infile) = howMany1(infile, 0);
Here, howMany1(infile,i) is an auxiliary that recursiively tries canInput with limits of i, i+1, and so on, until it finds that i for which there are exactly i characters waiting. A call by howMany to howMany1 with second argument 0 allows the exact number of waiting characters to be determined.

Exercise 4.2.2(a)

The first time, x is given the value "abc\nde\nf\n". The second and subsequent times executed, the value of x is the empty string.

Exercise 4.2.2(c)

The first time, x gets the value "ab". Subsequently, x is given the values "c\n", "de", "\nf", "\n", and "". Subsequent calls produce the empty string.

Exercise 4.2.2(e)

The first three calls produce for x the values "abc\n", "de\n", and "f\n". Subsequent calls produce the empty string as the value of x.

Exercise 4.2.3(a)

unit option

Exercise 4.2.3(c)

'a option option

Exercise 4.2.3(e)

fn : int option -> int

Exercise 4.2.4

     open TextIO;

     (* test if a character is white space *)
     fun white(" ") = true
     |   white("\t") = true
     |   white("\n") = true
     |   white(_) = false

     fun getWord(file) = (* read one word *)
     		if endOfStream(file) then ""
     		else
     			let
     				val c = inputN(file,1)
     			in
     				if white(c) then ""
     				else c^getWord(file)
     			end;

     fun getList1(file) = (* read all words from an instream *)
     		if endOfStream(file) then nil
     		else getWord(file) :: getList1(file);

     (* read all words from a file given the file name *)
     fun getList(filename) = getList1(openIn(filename));
Download this program

Return to Top

Solutions for Section 4.3

Exercise 4.3.1(b)

     val OUT = openAppend("/usr/spool/mail/fred");
This and the following solution assume that TextIO is already open.

Exercise 4.3.1(d)

     output(out2, "super");

Exercise 4.3.2

The following is one possible solution. We have written the code without opening structure TextIO, to give a sample showing that it is possible to do so.
     (* read digits until a nondigit and return their value
        assuming i is value of previously read digits
        of digits *)
     fun getInt(i,IN) =
             if not (isSome(TextIO.lookahead(IN))) then
                 i (* end of file reached *)
             else
                 let
                     val c = valOf(TextIO.input1(IN))
                 in
                     if c <= #"9" andalso c >= #"0" then (* c is a digit *)
                         getInt(10*i+ord(c)-ord(#"0"),IN)
                     else i
                 end;

     (* print integer i in decimal *)
     fun putInt1(i,OUT) =
             if i<10 then
                 TextIO.output(OUT, str(chr(i+ord(#"0"))))
             else (
                 putInt1(i div 10, OUT); (* print all but the last digit *)
                 putInt1(i mod 10, OUT)  (* print the last digit *)
             );

     (* print i, surrounding multidigit numbers by parens *)
     fun putInt(i,OUT) =
             if i<10 then
                 putInt1(i,OUT)
             else (
                 TextIO.output(OUT,"(");
                 putInt1(i,OUT);
                 TextIO.output(OUT,")")
             );

     (* convert i to a sequence of base-b digits and print *)
     fun convert1(i,b,OUT) =
             if i<b then putInt(i,OUT) else (
                 convert1(i div b, b, OUT);
                 putInt(i mod b, OUT)
             );

     (* read i and b and print i in base b *)
     fun convert(IN,OUT) =
             let
                 val i = getInt(0,IN);
                 val b = getInt(0,IN)
             in
                 convert1(i,b,OUT)
             end;
Download this program

Return to Top