# IronShell Functional Programming Utilities
# Higher-order functions and functional patterns
# ===== Currying and Partial Application =====
# Curry a binary function
# curry(fn(a, b) => a + b)(1)(2) == 3
pub let curry = fn(f) => fn(a) => fn(b) => f(a, b)
# Uncurry a curried function
# uncurry(fn(a) => fn(b) => a + b)(1, 2) == 3
pub let uncurry = fn(f) => fn(a, b) => f(a)(b)
# Apply first argument (partial application)
pub let partial = fn(f, x) => fn(y) => f(x, y)
# Apply second argument (partial application from right)
pub let partial_right = fn(f, y) => fn(x) => f(x, y)
# ===== Function Combinators =====
# Apply function twice
pub let twice = fn(f) => fn(x) => f(f(x))
# ===== Predicate Combinators =====
# Negate a predicate
pub let complement = fn(pred) => fn(x) => !pred(x)
# Both predicates must be true
pub let and_p = fn(p1, p2) => fn(x) => p1(x) && p2(x)
# Either predicate must be true
pub let or_p = fn(p1, p2) => fn(x) => p1(x) || p2(x)
# ===== Collection Utilities =====
# Drop first n elements; a negative n is refused.
# (There is no lib `find`: it would shadow the builtin `find` (file search) on
# import. For the first element matching a predicate, write arr | where(pred) | first.)
pub let drop = fn(arr, n) => match {
_ if n < 0 => error("drop: count must not be negative", {n: n}),
_ => arr | slice(n, len(arr))
}
# Export all public items
export {
curry, uncurry, partial, partial_right,
twice,
complement, and_p, or_p,
drop
}