sseletskyy
3/29/2017 - 9:11 PM

list-out-of-lambda.js

// Boolean logic

const tru = (t, f) => t()
const fals = (t, f) => f()

const not = x => (t, f) => x(f, t)
const and = (a, b) => (t, f) => a(
  () => b(t, f),
  () => f()
)
const or = (a, b) => (t, f) => a(
  () => t(),
  () => b(t, f)
)


// List basis

const emptyList = (selector) => selector(undefined, undefined, tru)
const prepend = (el, list) => (selector) => selector(el, list, fals)
const head    = (list) => list((h, t, e) => h)
const tail    = (list) => list((h, t, e) => t)
const isEmpty = (list) => list((h, t, e) => e)

const map = (list, fn) => isEmpty(list)(
  () => emptyList,
  () => prepend(fn(head(list)), map(tail(list), fn))
)

const filter = (list, fn) => isEmpty(list)(
  () => emptyList,
  () => fn(head(list))(
    () => prepend(head(list), filter(tail(list), fn)),
    () => filter(tail(list), fn)
  )
)


// Numbers

const zero = emptyList
const isZero = n => isEmpty(n)
const inc = n => prepend(emptyList, n)
const dec = n => tail(n)
const one = inc(zero)
const two = inc(one)

const add = (a, b) => isZero(b)(
  () => a,
  () => add(inc(a), dec(b))
)
const sub = (a, b) => isZero(b)(
  () => a,
  () => add(dec(a), dec(b))
)
const mul = (a, b) => isZero(b)(
  () => zero,
  () => add(a, mul(a, dec(b)))
)
const pow = (a, b) => isZero(b)(
  () => one,
  () => mul(a, pow(a, dec(b)))
)

const isEqual = (a, b) => and(isZero(a), isZero(b))(
  () => tru,
  () => or(isZero(a), isZero(b))(
    () => fals,
    () => isEqual(dec(a), dec(b))
  )
)
const lessThan = (a, b) => and(isZero(a), isZero(b))(
  () => fals,
  () => isZero(a)(
    () => tru,
    () => isZero(b)(
      () => fals,
      () => lessThan(dec(a), dec(b))
    )
  )
)
const greaterThan = (a, b) => lessThan(b, a)

const div = (a, b) => lessThan(a, b)(
  () => zero,
  () => inc(div(sub(a, b), b))
)
const rem = (a, b) => lessThan(a, b)(
  () => a,
  () => rem(sub(a, b), b)
)


// Array

const nth = (list, n) => isZero(n)(
  () => head(list),
  () => nth(tail(list), dec(n))
)
const length = (list) => isEmpty(list)(
  () => zero,
  () => inc(length(tail(list)))
)

const drop = (list, n) => isZero(n)(
  () => list,
  () => drop(tail(list), dec(n))
)
const take = (list, n) => isZero(n)(
  () => emptyList,
  () => prepend(head(list), take(tail(list), dec(n)))
)
const slice = (l, start, end) => take(drop(l, start), sub(end, start))