Skip to content

Instantly share code, notes, and snippets.

@dexterous
Last active May 29, 2025 11:28
Show Gist options
  • Save dexterous/e81e3d4e14ed0b3a2752f30c0ae07f28 to your computer and use it in GitHub Desktop.
Save dexterous/e81e3d4e14ed0b3a2752f30c0ae07f28 to your computer and use it in GitHub Desktop.
Lambda Combinators in JS
// https://en.wikipedia.org/wiki/Combinatory_logic#Examples_of_combinators
const I = a => a, // identity
K = a => _ => a, // constantly
V = a => b => c => c(a)(b), // cons
B = a => b => c => a(b(c)), // compose
S = x => y => z => x(z)(y(z)); // apply x to y inside env z
// alternative implementation of identity
const _I = S(K)(K)
// list processing
const cons = V, // cons(value)(tail) -> list(query) -> query(value)(tail)
end = _ => { throw "END" }; // end(query) -> throw "END"
const head = K, // list(constantly) -> constantly(value)(tail) -> value
next = K(I); // list(constantly(identity))
// -> constantly(identity)(value)(tail)
// -> identity(tail) -> tail
const evenOdd = cons('Even')(cons( 'Odd')(end)),
leftRight = cons('Left')(cons('Right')(end)),
yesNo = cons( 'Yes')(cons( 'No')(end));
console.log(evenOdd(head));
console.log(evenOdd(next)(head));
// console.log(evenOdd(next)(next)(head)) // throw "END"
console.log(yesNo(next)(head))
const integers = cons(0)(
cons(1)(
cons(2)(
cons(3)(
cons(4)(
end)))));
console.log('integers', integers(next)(next)(next)(head));
console.log('integers', integers(next)(next)(next)(head));
// segue: infinite lazy list
const lazyInts = i => cons(i)(_ => lazyInts(i+1)),
apply = f => f(), // doesn't take input(!)
lazyNext = K(apply);
console.log('lazyInts', lazyInts(0)(head))
console.log('lazyInts', lazyInts(0)(lazyNext)(lazyNext)(lazyNext)(head))
// lazyInts(1)(head) -> cons(1)(tail)(head)
// -> list(head)
// -> head(1)(tail)
// -> constantly(1)(tail)
// -> 1
// lazyInts(1)(lazyNext) -> cons(1)(_ => lazyInts(2))(constantly(apply))
// -> list(constantly(apply))
// -> constantly(apply)(1)(_ => lazyInts(2))
// -> apply(_ => lazyInts(2))
// -> lazyInts(2)
// segue: infinite iterative lazy list
const iterate = f => i => cons(i)(_ => iterate(f)(f(i))),
iterInts = iterate(i => i+1);
console.log('iterInts', iterInts(0)(head))
console.log('iterInts', iterInts(0)(lazyNext)(lazyNext)(lazyNext)(head))
// const tap = config => target => {
// config(target) // execute config for side effects
// return target // return the original value
// };
//
// console.log('value', tap(x => console.log('tap', x))(10));
const tap = S(K); // S(constantly)(config)(target)
// -> constantly(target)(config(target))
// -> targer # with config(target) side effects
console.log('value' , tap(x => console.log('tap', x))(10));
console.log('configured object', tap(o => o.foo = 'bar')(new Object()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment