(* * 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);