Functional programming

Table of contents

  1. Partial application
  2. Currying
  3. Fixed-point combinator
  4. Composition

Partial application

first  = |f,x| |y| f(x,y)
second = |f,y| |x| f(x,y)

# Variadic, fix first arguments
first = |f,*a| |*b| f(*(a+b))

# Variadic, fix last arguments
last  = |f,*a| |*b| f(*(b+a))

Currying

function curry(f)
  n = f.argc()
  a = list(0..n-1)
  g = fn|x| a[n-1]=x; f(*a) end
  for i in 2..n
    g = fn|x| a[n-i]=x; g end
  end
  return g
end

curry = fn|f|
  n = f.argc(); a = list(0..n-1)
  return (2..n).reduce(
    fn|x| a[n-1] = x; f(*a) end,
    |g,i| fn|x| a[n-i] = x; g end) end

uncurry = |f| |*a| a.reduce(f,|g,x| g(x))

Fixed-point combinator

# Y-combinator
fix = |F| (|x| x(x))(|x| F(|n| x(x)(n)))


# by built-in recursion
fix = |F| fn g|n| F(g)(n) end


# without currying
fix = |F| fn g|n| F(g,n) end


# with memoization
fix = fn|F|
  m = {}
  return fn g|n|
    if n not in m then m[n] = F(g,n) end
    return m[n]
  end
end


# one argument example: factorial function
fac = fix(|f| |n| 1 if n==0 else n*f(n-1))

# without currying
fac = fix(|f,n| 1 if n==0 else n*f(n-1))


# two argument example: integer power
pow = fix(|f| |[x,n]| 1 if n==0 else x*f([x,n-1]))

# without currying
pow = fix(|f,[x,n]| 1 if n==0 else x*f([x,n-1]))


for n in 0..10
  print([n,fac(n)])
end

for n in 0..10
  print([n,pow([2,n])])
end

Composition

Function.mpy = |g;f| |x| g(f(x))

compose = |*a| |x| a.rev().reduce(x,|y,f| f(y))

f = |x| 2*x
g = |x| x+1

print((g*f)(2))
print(compose(g,f)(2))