(*
 * day1.ml
 *
 *)

(*
 * The following example shows how definitions are permanent.
 * This is necessary to provide referential transparency.
 *)
val y = 6;

fun f(x:int):int = x + y;
f(2);

val y = 4;
f(2);		(* same as before *)

(*
 * Example of a function (fsum1) that receives another function (f) 
 * as parameter
 * fsum1 returns the sumation of applying f to the integers between 
 * 1 and m.
 *)
fun fsum1(f:(int->real),m:int):real = 
  let 
    (* sum is a local helper function *)
    (* note that sum is nested inside fsum *)
    fun sum(i:int, tot:real):real =
      if i > m then  (* m is picked from the parent environment *)
        tot
      else 
        sum(i+1, tot + (f(i)))
  in
    (* initial values *)
    sum(1, 0.0)
  end;

(*
 * fsum, another version.
 * Does not use a local function.
 * Recurses from m down to 0.
 *)
fun fsum2(f:(int->real),m:int):real =
  if m > 0 then
    f(m) + fsum2(f,m-1)
  else
    0.0;
    
(*
 * fsum, yet another version
 * Again, recurses from m down to 0.
 * This version uses patterns.  Note the | ("or") symbol.
 *)
fun fsum3(_, 0):real = 0.0
  | fsum3(f:(int->real),m:int) = f(m) + fsum3(f, m-1);
    
(*
 * One, always returns constant 1.0
 * Note type 'a, which means ANY type (cool!).
 * The simplest form of polymorphism.
 *)
fun One(x:'a):real = 1.0;

(*
 * Two, always returns constant 2.0
 *)
fun Two(x:'a):real = 2.0;

(*
 * invocation of fsum
 * fsum adds 10 times what One returns (10 times 1)
 *)
fsum1(One, 10); 

(*
 * another invocation of fsum
 * This one returns 20 (10 times 2).
 *)
fsum1(Two, 10);

(*
 * In this invocation of fsum, we define a function.
 * It is a function without a name.
 * Here it returns the sumation of the squares of integers
 * between 1 and 10.
 *)
fsum1(fn (k:int) => real(k*k), 10);

(*
 * Another invocation of fsum
 *)
fsum1(fn (k:int) => 6.0/real(k*k), 10);

(*
 * Giving names to functions
 *)
(* first an anonymous function (without a name) *)
fn (x:int) => x*x;
(* apply it to an integer *)
(fn (x:int) => x*x) 2;
(* give it a name *)
val square = fn (x:int) => x*x;
(* appply it *)
square 4;
(* now name it using fun, which makes it recursive and adds the
   possibility of handling patterns *)
fun square(x:int) = x*x;
(* apply it *)
square(5);

(*
 * Example of function composition
 *)
(* first, define function square *)
fun square(k:int):real = real(k*k);
(* now, redifine fsum in such a way that the function
   can be partially applied *)
fun fsum _ 0 = 0.0
  | fsum (f:(int->real)) (m:int) = f m + fsum f (m-1);

(* then define a new function which is the composition of
   fsum and square *)
val sumsq = fsum square;

(* and apply sumsq *)
sumsq(4);


    Source: geocities.com/htrefftz/mum/cs505/smlExamples

               ( geocities.com/htrefftz/mum/cs505)                   ( geocities.com/htrefftz/mum)                   ( geocities.com/htrefftz)