JavaScript + Flow Named Curried Functions
/* @flow */
const createPerson = ({}: { name: string, birth: Date, pets: number }): [] => []
const a = {};
//createPerson(a);
const b = { ...a, name: 'fred' };
//createPerson(b);
const c = { ...b, birth: new Date };
//createPerson(c);
const d = { ...c, pets: 0 };
createPerson(d);
function curryByName1(fun, accumulatedArgs) {
return Object.assign(
partialArgs => curryByName1(fun, { ...accumulatedArgs, ...partialArgs }),
{ accumulatedArgs, fun }
);
}
function curryByName2(fun, accumulatedArgs) {
return Object.assign(
partialArgs => curryByName2(fun, { ...accumulatedArgs, ...partialArgs }),
{ accumulatedArgs, fun }
);
}
function curryByName3(fun, accumulatedArgs) {
return Object.assign(
partialArgs => curryByName3(fun, { ...accumulatedArgs, ...partialArgs }),
{ accumulatedArgs, fun }
);
}
const x = curryByName1(createPerson, {})({ name: 'fred' })({ birth: new Date }).accumulatedArgs;
const y = curryByName2(createPerson, {})({ pets: 0 })({ birth: new Date }).accumulatedArgs;
const z = curryByName3(createPerson, {})({ pets: 0 })({ birth: new Date })({ name: 'fred' }).accumulatedArgs;
type CurriedByName<A: Object, O, AA: Object> = {
<P: Object>(partialArgs: P): CurriedByName<A, O, AA & P>,
accumulatedArgs: AA,
fun: (a: A) => O
};
function curryByName<A: Object, O>(fun: (a: A) => O): CurriedByName<A, O, {}> {
return (function curryByName_(fun, accumulatedArgs) {
return Object.assign(
partialArgs => curryByName_(fun, { ...accumulatedArgs, ...partialArgs }),
{ accumulatedArgs, fun, run: execCurriedByName }
);
})(fun, {});
}
const createPersonCurriedByName = curryByName(createPerson);
const m = createPersonCurriedByName({ name: 'fred' })({ birth: new Date });
//m.fun(m.accumulatedArgs);
const n = createPersonCurriedByName({ pets: 0 })({ birth: new Date });
//n.fun(n.accumulatedArgs);
const o = createPersonCurriedByName({ name: 'fred' })({ birth: new Date })({ pets: 0 });
o.fun(o.accumulatedArgs);
function execCurriedByName<A: Object, O>(curried: CurriedByName<A, O, A>): O { return curried.fun(curried.accumulatedArgs); }
//execCurriedByName(m);
//execCurriedByName(n);
const r = execCurriedByName(o);
// example
const run = execCurriedByName;
const curry = curryByName;
function pipe2<A,B,C>(f: (a: A) => B, g: (a: B) => C): (a: A) => C { return a => g(f(a)); }
type Color = 'red' | 'black';
class Car { wheels: number; color: Color; made: Date; }
const buildCarFrame = ({ wheels, color, made = new Date }: { wheels: number, color: Color, made?: Date }) => Object.assign(new Car, { wheels, color, made });
const buildCar = curry(buildCarFrame);
const roboticArm3WheelsRed = vehicle => vehicle({ wheels: 3, color: 'red' });
const roboticArm2Wheels = vehicle => vehicle({ wheels: 2 });
const roboticArmColor = color => vehicle => vehicle({ color });
const roboticArmVeteran = vehicle => vehicle({ made: new Date('1970') });
const pipeline1 = pipe2(roboticArmVeteran, roboticArm3WheelsRed);
const pipeline2 = pipe2(roboticArm2Wheels, roboticArmColor('green'));
const pipeline3 = vehicle => vehicle({ wheels: 6 });
const car1 = run(pipeline1(buildCar));
const car2 = run(pipeline2(buildCar));
//const car3 = run(roboticArmColor('re')(buildCar));
//const car4 = run(buildCar);
const car5unfinished = pipeline3(buildCar);
car5unfinished.accumulatedArgs;
run(car5unfinished) // SHOULD BE ERROR