(*
 * This file contains some simple test cases for exercising the looping
 * functions defined in ./loops.ml.  See also for.ml and while.ml for further
 * discussion.
 *)

use "loops.ml";
open Loops;

(*
 * The ML expression that follows is equivalent to the following C for-loop:
 *
 *     for (i=1; i<=10; i+=2) {
 *        printf("%d\n", i);
 *     }
 * 
 * or the following Modula-2 (Adaish, Pascalish) for-loop
 *
 *     for i:=1 to 10 by 2 do
 *        WriteInt(i,3); WriteLn;
 *     end;
 *
 * Note well the use of an anonymous (lambda) function to define the
 * for-loop body.  Chapter 11, pp. 103-4 of Ullman's ML discusses
 * anonymous functions in general.
 *)
for(1, 10, 2, nil, fn(i,x)=>
    (print(i); print("\n"); nil)
);

(*
 * The ML expression that follows is the equivalent of the (illegal) C program
 * discussed in the earlier comments.  Here's that example, this time in legal
 * C:
 *
 *    int i,k,result;
 *    k = 2;
 *    result = 1;
 *    for (i=1; i<=10; i++) {
 *        result *= i+k;
 *    }
 *
 * The similarity in style and size of the ML and C versions of this loop is
 * noteworthy, though it may take the C programmer a while to "appreciate" the
 * ML version.
 *
 *)
for(1, 10, 1, 1, fn(i, result)=>
    let
        val k = 2;
        val result = result * (i + k)
    in
        result
    end
);

(*
 * The preceding example would more likely be written as follows in C:
 *
 *    int i,k,result;
 *    for (i=1, k = 2, result = 1; i<=10; i++) {
 *        result *= i+k;
 *    }
 *
 * which has the following comparable form in ML:
 *)
for(1, 10, 1, (2, 1), fn(i, (k, result)) =>
    let val result = result * (i + k)
    in (k, result) end
);


(*
 * Additional example uses of for loops follow.
 *)
forl(1, 10, 1, 1, fn(i, result) =>
    let val k=2; val result = result * (i + k)
    in result end
);

foreach ([1,2,3], 0, fn(x,result)=>
    let val result = result+x in result end);

val l = [1,2,3,4,5,6,7,8];
val (sum, product, count, avg) =
    foreach (l, (0,1,0,0.0), fn(item, (sum, product, count, avg:real)) =>
        let
            val sum = sum + item;
            val product = product * item;
            val count = count + 1;
            val avg = real(sum)/real(count);
        in
            (sum, product, count, avg)
        end);


(*
 * Some while loop examples.
 *)
while1 (fn(x,y)=>(x<y), (1, 10), fn(x, y)=>
    let
	val x = x + 1;
    in
	print(x-1);
	print("\n");
	(x,y)
    end
);

fun less(x:int,y) = x<y;
fun body1(x:int,y) =
    let
        val x = x + 1;
    in
	print(x-1);
	print("\n");
        (x,y)
    end;
val initxy = (1,10);
while1(less, initxy, body1) ;


(*
 * A simple example of plain loop usage.  It's equivalent to the following
 * Pascalese:
 *
 *    program
 *        var n: integer;
 *    begin
 *        n := 0;
 *        loop
 *            n := n+1;
 *            WriteInt(n,0);
 *            WriteLn;
 *            if n>10 then exit end;
 *        end;
 *    end.
 *
 *)
exception ExitLoop;
loop(0, fn(n)=>
    let
	val n = n+1
    in
	print(n);
	print("\n");
	if n>10 then raise ExitLoop else n
    end);