08_Combinators

Combinator-Based Architecture

What is Combinator-Based Architecture?

Combinator-based architecture means the entire language is built from simple, composable functions called combinators. There are no classes, no inheritance, no methods - everything is function composition.

/* Everything is built from combinators */
/* map, filter, reduce, compose, pipe, each, via */
/* No classes, no inheritance, no methods */

Why is This Esoteric?

Most programming languages are built around objects, classes, and methods. Our language is built entirely around function composition and combinators - a completely different paradigm.

Core Combinators

map - Transform Elements

/* map applies a function to every element in a collection */
double : x -> x * 2;
numbers : {1, 2, 3, 4, 5};
doubled : map @double numbers;  /* {2, 4, 6, 8, 10} */

/* map works with any function */
increment : x -> x + 1;
incremented : map @increment numbers;  /* {2, 3, 4, 5, 6} */

filter - Select Elements

/* filter keeps elements that satisfy a condition */
is_even : x -> x % 2 = 0;
numbers : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
evens : filter @is_even numbers;  /* {2, 4, 6, 8, 10} */

/* filter with custom conditions */
is_greater_than_five : x -> x > 5;
large_numbers : filter @is_greater_than_five numbers;  /* {6, 7, 8, 9, 10} */

reduce - Accumulate Elements

/* reduce combines all elements into a single value */
numbers : {1, 2, 3, 4, 5};
sum : reduce @add 0 numbers;  /* 15 */
product : reduce @multiply 1 numbers;  /* 120 */

/* reduce with custom accumulation */
max_value : reduce @max 0 numbers;  /* 5 */
min_value : reduce @min 1000 numbers;  /* 1 */

each - Multi-Argument Operations

/* each applies a function to corresponding elements from multiple collections */
numbers1 : {1, 2, 3, 4, 5};
numbers2 : {10, 20, 30, 40, 50};

/* Element-wise addition */
sums : each @add numbers1 numbers2;  /* {11, 22, 33, 44, 55} */

/* Element-wise multiplication */
products : each @multiply numbers1 numbers2;  /* {10, 40, 90, 160, 250} */

Function Composition Combinators

compose - Mathematical Composition

/* compose(f, g)(x) = f(g(x)) */
double : x -> x * 2;
increment : x -> x + 1;
square : x -> x * x;

/* Compose functions */
double_then_increment : compose @increment @double;
increment_then_square : compose @square @increment;

/* Use composed functions */
result1 : double_then_increment 5;  /* double(5)=10, increment(10)=11 */
result2 : increment_then_square 5;  /* increment(5)=6, square(6)=36 */

pipe - Pipeline Composition

/* pipe(f, g)(x) = g(f(x)) - left to right */
double_then_square : pipe @double @square;
result : double_then_square 5;  /* double(5)=10, square(10)=100 */

via - Natural Composition

/* via provides natural composition syntax */
complex_transform : double via increment via square;
result : complex_transform 3;  /* square(3)=9, increment(9)=10, double(10)=20 */

Building Complex Operations

Data Processing Pipeline

/* Build complex operations from simple combinators */
data : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

/* Pipeline: filter → map → reduce */
is_even : x -> x % 2 = 0;
double : x -> x * 2;
sum : x -> reduce @add 0 x;

/* Combine combinators */
pipeline : sum via map @double via filter @is_even;
result : pipeline data;  /* 60 */

/* Step by step:
   1. filter @is_even data → {2, 4, 6, 8, 10}
   2. map @double {2, 4, 6, 8, 10} → {4, 8, 12, 16, 20}
   3. sum {4, 8, 12, 16, 20} → 60
*/

Validation Chain

/* Build validation from combinators */
validate_positive : x -> x > 0;
validate_even : x -> x % 2 = 0;
validate_small : x -> x < 10;

/* Chain validations */
all_validations : validate_small via validate_even via validate_positive;
result : all_validations 6;  /* true (6 > 0, 6 % 2 = 0, 6 < 10) */

Table-Specific Combinators

The t. namespace provides table-specific combinators:

/* Table operations as combinators */
data : {a: 1, b: 2, c: 3};

/* Get keys and values */
keys : t.keys data;  /* {"a", "b", "c"} */
values : t.values data;  /* {1, 2, 3} */

/* Check and get values */
has_a : t.has data "a";  /* true */
value_a : t.get data "a";  /* 1 */

/* Transform tables */
with_d : t.set data "d" 4;  /* {a: 1, b: 2, c: 3, d: 4} */
without_b : t.delete data "b";  /* {a: 1, c: 3} */

/* Merge tables */
table1 : {a: 1, b: 2};
table2 : {c: 3, d: 4};
merged : t.merge table1 table2;  /* {a: 1, b: 2, c: 3, d: 4} */

Advanced Combinator Patterns

Function Factories

/* Create combinators that generate other combinators */
create_multiplier : factor -> multiply factor;
double : create_multiplier 2;
triple : create_multiplier 3;

/* Use generated combinators */
numbers : {1, 2, 3, 4, 5};
doubled : map @double numbers;  /* {2, 4, 6, 8, 10} */
tripled : map @triple numbers;  /* {3, 6, 9, 12, 15} */

Conditional Combinators

/* Combinators that choose based on conditions */
conditional_map : condition transform_false transform_true -> 
  when condition is
    true then transform_true
    _ then transform_false;

/* Use conditional combinator */
is_positive : x -> x > 0;
double : x -> x * 2;
square : x -> x * x;

conditional_transform : conditional_map is_positive @square @double;
result : map conditional_transform {1, -2, 3, -4, 5};
/* Result: {1, -4, 9, -8, 25} (positive numbers squared, negative doubled) */

Recursive Combinators

/* Combinators that can be applied recursively */
repeat_transform : n transform -> 
  when n is
    0 then identity
    _ then compose transform (repeat_transform (n - 1) transform);

/* Use recursive combinator */
double : x -> x * 2;
double_three_times : repeat_transform 3 @double;
result : double_three_times 5;  /* 40 (5 * 2 * 2 * 2) */

When to Use Combinators

Use combinators when:

  • Processing collections of data
  • Building data transformation pipelines
  • Creating reusable function components
  • Working with functional programming patterns
  • Building complex operations from simple ones

Don't use combinators when:

  • You need side effects (combinators are pure)
  • You need complex object-oriented patterns
  • You're working with simple, one-off operations
  • You need imperative control flow

Common Patterns

/* Pattern 1: Data transformation pipeline */
data : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

/* Build pipeline from combinators */
pipeline : sum via map @double via filter @is_even;
result : pipeline data;  /* 60 */

/* Pattern 2: Validation pipeline */
validate_user : user -> 
  all_validations : validate_email via validate_age via validate_name;
  all_validations user;

/* Pattern 3: Configuration builder */
build_config : base_config overrides -> 
  t.merge base_config overrides;

Key Takeaways

  1. Function composition - everything is built from function composition
  2. No objects - no classes, inheritance, or methods
  3. Composable - combinators can be combined into complex operations
  4. Pure functions - no side effects, predictable behavior
  5. Mathematical thinking - operations are mathematical transformations

Why This Matters

Combinator-based architecture makes the language fundamentally different:

  • Mathematical foundation - based on function theory and category theory
  • Composability - complex operations built from simple, reusable parts
  • Predictability - pure functions with no side effects
  • Functional thinking - encourages thinking in terms of transformations
  • No state management - no mutable state to manage

This architecture makes the language feel more like mathematical notation than traditional programming! 🚀