Standard Toolkit
Packages@accelint/coreCombinators

fork

Passes a value through two functions and combines their results

Passes a value through two different functions and combines their results with a binary function. Also known as the Phi (Φ) combinator in lambda calculus.

Usage

import { fork } from '@accelint/core';

// Fork a value through two functions
const result = fork((x: number) => (y: number) => x + y)
  ((x: number) => x + 3)
  ((x: number) => x - 2)
  (9);
// 19 (9+3=12, 9-2=7, 12+7=19)

// Partial application
const computeSum = fork((x: number) => (y: number) => x + y);
computeSum((x: number) => x * 2)((x: number) => x + 1)(5);
// 16 (5*2=10, 5+1=6, 10+6=16)

Reference

function fork<A, B, C>(
  a: (x: A) => (y: B) => C
): <D>(b: (x: D) => A) => (c: (x: D) => B) => (d: D) => C

Lambda calculus: λabcd.a(bd)(cd)
Type signature: fork :: (a → b → c) → (d → a) → (d → b) → d → c

Parameters

ParameterTypeDescription
a(x: A) => (y: B) => CThe binary function that combines the results.
b(x: D) => AThe first function to apply to the value.
c(x: D) => BThe second function to apply to the value.
dDThe value to fork through both functions.

Returns

Returns the result of a(b(d))(c(d)).

Type Parameters

  • A - The return type of function b and first input to a
  • B - The return type of function c and second input to a
  • C - The return type of the combining function a
  • D - The type of the input value

Examples

Example: Computing statistics

import { fork } from '@accelint/core';

const stats = fork((sum: number) => (count: number) => ({
  sum,
  count,
  average: count > 0 ? sum / count : 0
}));

const computeStats = (numbers: number[]) =>
  stats
    ((arr: number[]) => arr.reduce((a, b) => a + b, 0))
    ((arr: number[]) => arr.length)
    (numbers);

computeStats([1, 2, 3, 4, 5]);
// { sum: 15, count: 5, average: 3 }

Example: Validation with multiple rules

import { fork } from '@accelint/core';

interface ValidationResult {
  hasMinLength: boolean;
  hasMaxLength: boolean;
  isValid: boolean;
}

const validateString = fork((min: boolean) => (max: boolean): ValidationResult => ({
  hasMinLength: min,
  hasMaxLength: max,
  isValid: min && max
}));

const validate = validateString
  ((s: string) => s.length >= 3)
  ((s: string) => s.length <= 10);

validate('hi'); // { hasMinLength: false, hasMaxLength: true, isValid: false }
validate('hello'); // { hasMinLength: true, hasMaxLength: true, isValid: true }

Example: Parallel transformations

import { fork } from '@accelint/core';

interface User {
  firstName: string;
  lastName: string;
}

const formatUser = fork((first: string) => (last: string) => `${first} ${last}`);

const getFormattedName = formatUser
  ((u: User) => u.firstName.toUpperCase())
  ((u: User) => u.lastName.toUpperCase());

getFormattedName({ firstName: 'john', lastName: 'doe' });
// 'JOHN DOE'

Example: Combining calculations

import { fork } from '@accelint/core';

const calculateDiscount = fork((price: number) => (discount: number) => price * (1 - discount));

interface Product {
  price: number;
  category: string;
}

const getCategoryDiscount = (category: string): number => {
  return category === 'electronics' ? 0.1 : 0.05;
};

const applyDiscount = calculateDiscount
  ((p: Product) => p.price)
  ((p: Product) => getCategoryDiscount(p.category));

applyDiscount({ price: 100, category: 'electronics' });
// 90 (10% discount)

Good to know: The fork combinator is useful when you need to apply multiple transformations to the same input and combine their results. It avoids recomputing the input or storing intermediate values.

  • composition - Compose two functions
  • apply - Apply function to value
  • pipe - Compose functions left-to-right

On this page