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

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

Parsing combinators

Alternation: grammar * grammar -> grammar

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.

```
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