Lecture 010

Point-free Programming

Point-free: function as data

(*
compose: ('b -> 'c) * ('a -> 'b) -> 'a -> 'c

*)
fun compose (f, g) = fn x => f(g x)

Point-wise operation define f +- g by (f+=g) (x) = f(x) +- g(x)

(*
op ++: ('a -> int) * ('a -> int) -> ('a -> int)
*)
fun ++ (f, g) = fn x => f x + g x
fun ++ (f, g) x = f x + g x
fun MIN (f, g) x = Int.min(f x, g x)

So that we can write these

val a = square ++ twice
val b = MIN(square, twice)

where those are new composed function

More Advanced

Combinator: a small function that is useful for building up functionality from small pieces

Parsing combinators

Alternation: grammar * grammar -> grammar

Staging

A slow function

fun f (x : int, y : int) = let
    val z = very_slow_computation (x)
  in
    z+y
  end

Another slow function: function g is only evaluated when both x and y are present.

fun g (x : int) (y : int) : int =
  let
    val z = very_slow_computation (x)
  in
    z+y
  end

in fact while val g5 = g 5 is fast (it just a function with one extra environment binding) but val g57 = g 5 7 is slow. So what is the benifit of using function g instead f?

Imagine we need to calculate both val f57 = f 5 7 and val f58 = f 5 8 and very_slow_computation takes about 1 year. If we are constrained to use function f or function g, then if we will at least take 2 years to finish. But if we use function h. we can first calculate val h5 = h 5 and then calculate val h57 = h5 7 and val h58 = h5 8, then we can finish in 1 year.

fun h (x : int) : int -> int =
  let
    val z = very_slow_computation (x)
  in
    fn y : int => z + y
  end

This is good: function h is evaluated as soon as x is present.

Map

fun map f l = foldr (fn (x, l') => f x :: l') [] l
fun foldr f b nil = b
  | foldr f b (x::xs) = f (x, foldr f b xs)

when f = ::, then it is folding a list

catamorphism: generalized fold

We write our tree fold

(* tfold: ('b * 'a * 'b -> 'b) -> 'b -> 'a tree -> 'b *)
fun tfold f b Empty = b
  | tfold f b (Node(l, x, r)) = f (tfold f b l, x, tfold f b r)

building tmap using tfold

fun tmap f T = tfold (fn (l, x, r) => Node(l, f x, r)) (Empty) T
fun tsum (T : int tree): int = tfold (ftold (fun (l, x, r) => l + x + r)) (0) T
fun size (T: 'a tree) : int = tfold (fn (l, x, r) => (l + r+ 1)) 0 T
fun depth (T: 'a tree) : int = tfold (fn (l, x, r) => Int.max(l, r) + 1) - T

Table of Content