# Currying Pattern

## Problem

You have functions that take multiple arguments, but you often want to fix some arguments and reuse the partially-applied function. Without currying, you end up writing many small wrapper functions manually.

## Solution

**Currying** transforms a function that takes multiple arguments into a chain of functions, each taking a single argument. **Partial application** is the related concept of fixing some arguments to produce a new function with fewer parameters.

## When to Use

- Creating specialized versions of generic functions (e.g., `add(1)` becomes `increment`)
- Building configurable function pipelines
- Event handlers where some context is known at registration time
- Dependency injection at the function level

## When to Avoid

- When it hurts readability (over-currying makes call sites cryptic)
- Performance-sensitive code where closure allocation matters
- Simple functions where direct calls are clearer

## Pseudocode

```
// Currying: f(a, b, c) becomes f(a)(b)(c)
function add(a):
    return function(b):
        return a + b

increment = add(1)
print(increment(5))   // 6

// Partial application
function greet(greeting, name):
    return greeting + ", " + name + "!"

sayHello = partial(greet, "Hello")
print(sayHello("Alice"))  // "Hello, Alice!"
```

## Python

```python
from functools import partial
from typing import Callable

# Manual currying
def add(a: int) -> Callable[[int], int]:
    def inner(b: int) -> int:
        return a + b
    return inner

# Generic curry decorator
def curry(fn: Callable) -> Callable:
    import inspect
    arity = len(inspect.signature(fn).parameters)

    def curried(*args):
        if len(args) >= arity:
            return fn(*args)
        return lambda *more: curried(*args, *more)

    return curried

@curry
def multiply(a: int, b: int, c: int) -> int:
    return a * b * c

def greet(greeting: str, name: str) -> str:
    return f"{greeting}, {name}!"

def main() -> None:
    # Manual currying
    increment = add(1)
    add_ten = add(10)
    print(f"increment(5) = {increment(5)}")
    print(f"add_ten(5) = {add_ten(5)}")

    # Curried multiply
    double = multiply(2)(1)  # 2 * 1 * c
    print(f"multiply(2)(3)(4) = {multiply(2)(3)(4)}")
    print(f"double = multiply(2)(1), double(7) = {double(7)}")

    # functools.partial
    say_hello = partial(greet, "Hello")
    say_hi = partial(greet, "Hi")
    print(f"say_hello('Alice') = {say_hello('Alice')}")
    print(f"say_hi('Bob') = {say_hi('Bob')}")

    # Practical: configurable formatter
    def format_number(prefix: str, decimals: int, value: float) -> str:
        return f"{prefix}{value:.{decimals}f}"

    format_usd = partial(format_number, "$", 2)
    format_eur = partial(format_number, "EUR ", 2)
    format_pct = partial(format_number, "", 1)

    print(f"\nformat_usd(1234.5) = {format_usd(1234.5)}")
    print(f"format_eur(1234.5) = {format_eur(1234.5)}")
    print(f"format_pct(99.876) = {format_pct(99.876)}%")

    # Pipeline with curried functions
    numbers = [1, 2, 3, 4, 5]
    add_one = add(1)
    result = list(map(add_one, numbers))
    print(f"\nmap(add(1), {numbers}) = {result}")

if __name__ == "__main__":
    main()
```

## Go

```go
package main

import "fmt"

// Curried add: add(a)(b)
func add(a int) func(int) int {
	return func(b int) int {
		return a + b
	}
}

// Curried multiply: multiply(a)(b)(c)
func multiply(a int) func(int) func(int) int {
	return func(b int) func(int) int {
		return func(c int) int {
			return a * b * c
		}
	}
}

// Curried greeter
func greet(greeting string) func(string) string {
	return func(name string) string {
		return fmt.Sprintf("%s, %s!", greeting, name)
	}
}

// Generic partial application using closures
func formatNumber(prefix string, decimals int) func(float64) string {
	return func(value float64) string {
		format := fmt.Sprintf("%s%%.%df", prefix, decimals)
		return fmt.Sprintf(format, value)
	}
}

func main() {
	// Curried add
	increment := add(1)
	addTen := add(10)
	fmt.Printf("increment(5) = %d\n", increment(5))
	fmt.Printf("addTen(5) = %d\n", addTen(5))

	// Curried multiply
	fmt.Printf("multiply(2)(3)(4) = %d\n", multiply(2)(3)(4))
	double := multiply(2)(1)
	fmt.Printf("double(7) = %d\n", double(7))

	// Curried greeter
	sayHello := greet("Hello")
	sayHi := greet("Hi")
	fmt.Printf("sayHello(\"Alice\") = %s\n", sayHello("Alice"))
	fmt.Printf("sayHi(\"Bob\") = %s\n", sayHi("Bob"))

	// Configurable formatter
	formatUSD := formatNumber("$", 2)
	formatEUR := formatNumber("EUR ", 2)
	formatPct := formatNumber("", 1)

	fmt.Printf("\nformatUSD(1234.5) = %s\n", formatUSD(1234.5))
	fmt.Printf("formatEUR(1234.5) = %s\n", formatEUR(1234.5))
	fmt.Printf("formatPct(99.876) = %s%%\n", formatPct(99.876))

	// Pipeline with curried functions
	numbers := []int{1, 2, 3, 4, 5}
	addOne := add(1)
	result := make([]int, len(numbers))
	for i, n := range numbers {
		result[i] = addOne(n)
	}
	fmt.Printf("\nmap(add(1), %v) = %v\n", numbers, result)
}
```

## JavaScript

```javascript
// Curried add using arrow functions
const add = (a) => (b) => a + b;

// Curried multiply
const multiply = (a) => (b) => (c) => a * b * c;

// Curried greeter
const greet = (greeting) => (name) => `${greeting}, ${name}!`;

// Generic curry utility
function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn(...args);
    }
    return (...moreArgs) => curried(...args, ...moreArgs);
  };
}

// Configurable formatter (non-curried, then curried)
function formatNumber(prefix, decimals, value) {
  return `${prefix}${value.toFixed(decimals)}`;
}

const curriedFormat = curry(formatNumber);

function main() {
  // Curried add
  const increment = add(1);
  const addTen = add(10);
  console.log(`increment(5) = ${increment(5)}`);
  console.log(`addTen(5) = ${addTen(5)}`);

  // Curried multiply
  console.log(`multiply(2)(3)(4) = ${multiply(2)(3)(4)}`);
  const double = multiply(2)(1);
  console.log(`double(7) = ${double(7)}`);

  // Curried greeter
  const sayHello = greet("Hello");
  const sayHi = greet("Hi");
  console.log(`sayHello("Alice") = ${sayHello("Alice")}`);
  console.log(`sayHi("Bob") = ${sayHi("Bob")}`);

  // Generic curry utility
  const formatUSD = curriedFormat("$")(2);
  const formatEUR = curriedFormat("EUR ")(2);
  const formatPct = curriedFormat("")(1);

  console.log(`\nformatUSD(1234.5) = ${formatUSD(1234.5)}`);
  console.log(`formatEUR(1234.5) = ${formatEUR(1234.5)}`);
  console.log(`formatPct(99.876) = ${formatPct(99.876)}%`);

  // Pipeline with curried functions
  const numbers = [1, 2, 3, 4, 5];
  const addOne = add(1);
  const result = numbers.map(addOne);
  console.log(`\nmap(add(1), [${numbers}]) = [${result}]`);

  // Compose curried functions
  const pipe =
    (...fns) =>
    (x) =>
      fns.reduce((v, f) => f(v), x);
  const transform = pipe(add(1), multiply(2)(3));
  console.log(`pipe(add(1), multiply(2)(3))(4) = ${transform(4)}`);
}

main();
```

## Related Patterns

- **Partial Application** — partial application fixes some arguments of a function; currying is the structural mechanism that makes partial application systematic.
- **Higher-Order Functions** — curried functions are higher-order functions; currying and HOFs are deeply interrelated.
- **Builder** — a curried builder applies configuration arguments one at a time, building up an object fluently.
