04_Currying

Currying

What is Partial Application?

Partial application means that functions automatically return new functions when called with fewer arguments than they expect. This is also called currying.

/* Functions automatically return new functions when partially applied */
add : x y -> x + y;
add_five : add 5;  /* Returns a function that adds 5 */
result : add_five 3;  /* 8 */

Most programming languages require explicit syntax for partial application or currying. When using Baba Yagay, every function is automatically curried.

Basic Examples

/* Define a two-argument function */
add : x y -> x + y;

/* Call with both arguments */
result1 : add 5 3;  /* 8 */

/* Call with one argument - returns a new function */
add_five : add 5;  /* Returns: y -> 5 + y */

/* Call the returned function */
result2 : add_five 3;  /* 8 */

/* Chain partial applications */
add_ten : add 10;  /* y -> 10 + y */
add_ten_five : add_ten 5;  /* 15 */

How It Works

Partial application happens automatically with nested function returns.

/* When you define: add : x y -> x + y; */
/* Baba Yaga creates: add = x -> (y -> x + y) */

/* When you call: add 5 */
/* It returns: y -> 5 + y */

/* When you call: add 5 3 */
/* It calls: (y -> 5 + y)(3) = 5 + 3 = 8 */

Partial application works with any number of arguments.

/* Three-argument function */
multiply_add : x y z -> x * y + z;

/* Partial application examples */
multiply_by_two : multiply_add 2;  /* y z -> 2 * y + z */
multiply_by_two_add_ten : multiply_add 2 5;  /* z -> 2 * 5 + z */

/* Full application */
result1 : multiply_add 2 5 3;  /* 2 * 5 + 3 = 13 */
result2 : multiply_by_two 5 3;  /* 2 * 5 + 3 = 13 */
result3 : multiply_by_two_add_ten 3;  /* 2 * 5 + 3 = 13 */

All standard library functions support partial application, too!

/* Arithmetic functions */
double : multiply 2;  /* x -> 2 * x */
increment : add 1;    /* x -> x + 1 */
decrement : subtract 1;  /* x -> x - 1 */

/* Comparison functions */
is_positive : greaterThan 0;  /* x -> x > 0 */
is_even : equals 0;  /* This won't work as expected - see below */

/* Logical functions */
always_true : logicalOr true;  /* x -> true || x */
always_false : logicalAnd false;  /* x -> false && x */

Common Patterns

/* Pattern 1: Creating specialized functions */
numbers : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

/* Create specialized filters */
is_even : x -> x % 2 = 0;
is_odd : x -> x % 2 = 1;
is_greater_than_five : x -> x > 5;

/* Use with map and filter - note the @ operator for higher-order functions */
evens : filter @is_even numbers;  /* {2, 4, 6, 8, 10} */
odds : filter @is_odd numbers;    /* {1, 3, 5, 7, 9} */
large_numbers : filter @is_greater_than_five numbers;  /* {6, 7, 8, 9, 10} */

/* Pattern 2: Creating transformation functions */
double : multiply 2;
triple : multiply 3;
add_ten : add 10;

/* Apply transformations - @ operator required for map */
doubled : map @double numbers;  /* {2, 4, 6, 8, 10, 12, 14, 16, 18, 20} */
tripled : map @triple numbers;  /* {3, 6, 9, 12, 15, 18, 21, 24, 27, 30} */
plus_ten : map @add_ten numbers;  /* {11, 12, 13, 14, 15, 16, 17, 18, 19, 20} */

You can use partial application with function composition.

/* Create specialized functions */
double : multiply 2;
increment : add 1;
square : x -> x * x;

/* Compose partially applied functions - @ operator required for compose */
double_then_increment : compose @increment @double;
increment_then_square : compose @square @increment;

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

Table Operations with Partial Application

The t. namespace functions also support partial application:

/* Create specialized table operations */
get_name : t.get "name";
get_age : t.get "age";
has_admin : t.has "admin";

/* Use with map - @ operator required for higher-order functions */
people : {
  alice: {name: "Alice", age: 30, admin: true},
  bob: {name: "Bob", age: 25, admin: false},
  charlie: {name: "Charlie", age: 35, admin: true}
};

names : map @get_name people;  /* {alice: "Alice", bob: "Bob", charlie: "Charlie"} */
ages : map @get_age people;    /* {alice: 30, bob: 25, charlie: 35} */
admins : map @has_admin people;  /* {alice: true, bob: false, charlie: true} */

The each Combinator with Partial Application

The each combinator works well with partial application:

/* Create specialized comparison functions */
is_greater_than_three : x -> x > 3;
is_less_than_seven : x -> x < 7;

/* Use with each for element-wise comparison - @ operator required for each */
numbers : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

greater_than_three : each @is_greater_than_three numbers;
/* Result: {false, false, false, true, true, true, true, true, true, true} */

less_than_seven : each @is_less_than_seven numbers;
/* Result: {true, true, true, true, true, true, false, false, false, false} */