-- Square and Increment functions

let square = \x -> x*x
let increment = \x -> x+1

---- Combinators

-- Identity combinator

let i = \x -> x

i 5

i square 5

let sq = i square

sq 5

-- Application combinator

let app = \f -> \x -> f x

app square 7

let sq = app square

sq 7

-- Sequencing combinator, z should not appear free in e2

let seq e1 e2 = (\z ->  e2) e1

seq 3 4

-- Currying is first class in Haskell

let plus x y = x+y

-- equivalent to

let plus = \x -> \y -> x+y

plus 4 5

let plus2 = plus 2

plus2 3

-- Function composition combinator

-- the following four are equivalent forms:

let compose f g x =  f (g x)

let compose f g = \x ->  f (g x)

let compose f = \g -> \x ->  f (g x)

let compose = \f -> \g -> \x ->  f (g x)

compose square increment 5

-- Currying compose (applying it to less arguments):
 
let incrementC = compose increment

let squaredPlusOne = incrementC square

-- same as

let squaredPlusOne = compose increment square

squaredPlusOne 4

let incrementTwice = incrementC increment

incrementTwice 5

-- Using curried compose increment with an anonymous function:

incrementC (\x -> x+2) 4

incrementC (+2) 5
