An Introduction to FP Through Lambda Calculus (JS)
Índice
Código en JavaScript del libro An Introduction to Functional Programming Through Lambda Calculus. Posiblemente (casi seguro al 100%) solamente los ejemplos pero no los ejercicios.
Introducción
Función Identidad
const id = x => x; console.log(id(1) == 1); console.log(id(id)(1) == 1);
Auto-aplicación
// Ya definido / `session` not supported for node.js const id = x => x; // Nuevo const selfAp = s => s(s); console.log(selfAp(id)(1) == 1)
La autoaplicación s(id)
es igual a la aplicación anterior de id
en id
. Si expandimos:
s(id) *> (s => s(s))(id) *> s:id => s(s) *> id(id) *> (x => x)(id) *> x:id => x *> id
Con s:id
quiero decir que s se va a sustituir por id.
Aplicación de una función
// Ya definido const id = x => x; const selfAp = s => s(s); // Nuevo const apply = f => x => f(x); console.log(apply(id)(1) == 1); console.log(apply(selfAp(id))(2) == 2);
Función de orden superior que recibe función, y devuelve otra función. Esta función de salida se encarga de aplicar la primera función que pasamos como argumento inicial al parámetro que se le pase.
Selección de elementos y Tuplas
// Ya definido const id = x => x; const selfAp = s => s(s); const apply = f => x => f(x); // Nuevo const first = x => y => x; const second = x => y => y; const makePair = x => y => f => f(x)(y) console.log(first(1)(2) == 1); console.log(second(1)(2) == 2); console.log(makePair(1)(2)(first) == 1); console.log(makePair(1)(2)(second) == 2); const makeTriplet = x => y => z => f => f(x)(y)(z); const tripletFirst = x => y => z => x; const tripletSecond = x => y => z => y; const tripletThird = x => y => z => z; console.log(tripletFirst(1)(2)(3) == 1); console.log(tripletSecond(1)(2)(3) == 2); console.log(tripletThird(1)(2)(3) == 3); console.log(makeTriplet(1)(2)(3)(tripletFirst) == 1); console.log(makeTriplet(1)(2)(3)(tripletSecond) == 2); console.log(makeTriplet(1)(2)(3)(tripletThird) == 3);
Condicionales, booleanos y números
Condicional
A partir del ternario es muy fácil definir el condicional
const cond = x => y => c => c(x)(y)
Booleanos
// Ya definido const id = x => x; const selfAp = s => s(s); const apply = f => x => f(x); const first = x => y => x; const second = x => y => y; const makePair = x => y => f => f(x)(y); // Nuevo const True = first; const False = second; console.log(True(1)(2)) console.log(False(1)(2))
Operadores Lógicos
Not
Not nos permite elegir entre un par de valores False/True.
X ? False : True
Como espera un booleano, si es verdadero devuelve False, si recibe falso devuelve True. Con esto es muy fácil darse cuenta que simplemente necesitamos seleccionar el segundo cuando pasemos falso, y el primero cuando verdadero. Como True ~ first
y False ~ second
, entonces lo tenemos hecho.
// Ya definido const cond = x => y => c => c(x)(y); // Aquí expando en vez de hacer alias para mejor salida de la ejecución del código. const True = x => y => x; const False = x => y => y; // Nuevo // x es un booleano, en ts sería // const not = (x: bool) => x(second)(first) // const not = x => x(second)(first) const not = x => x(False)(True); console.log('----'); console.log(not(True)); console.log(not(False));
And/Or
Para and, si la condición es verdadero devolvemos el segundo, y si es falsa podemos devolver o bien la misma condición (por ser falsa) o mejor falso directamente por si la evaluación fuese perezosa y no hubiese cacheado de resultados.
// Ya definido const cond = x => y => c => c(x)(y); const True = x => y => x; const False = x => y => y; // Nuevo const and = x => y => x(y)(False) const or = x => y => x(True)(y) console.log('----') console.log(and(True)(False)) console.log(and(True)(True)) console.log(and(False)(True)) console.log(and(False)(False)) console.log(or(True)(False)) console.log(or(True)(True)) console.log(or(False)(True)) console.log(or(False)(False))
La traducción es directa desde los equivalentes en ternario, x ? y : false
, x ? true : y
.
Números
Se define el cero, y a partir de ahí el resto como sucesores del cero.
// Ya definido const id = x => x; const first = x => y => x; const second = x => y => y; const True = first; const False = second; // Nuevo // básicos const zero = id; const succ = n => s => s(False)(n); const isZero = n => n(first); // first // derivados const one = succ(zero); const two = succ(one); console.log('----'); console.log(isZero(zero)); // first ~ True console.log(isZero(one)); // second ~ False console.log(isZero(two)); // second ~ False