.curried & .uncurried
Fully typed currying as extension getters — the Dart-native replacement for FxTS curry.
Lecture
Currying turns a function of several arguments into a chain of unary
functions: add(1, 2) becomes add.curried(1)(2).
The payoff is partial application — fixing the first
argument yields a new function, which is exactly the shape callbacks like
map and filter want.
FxTS ships this as a function, curry(f), built on two things
Dart doesn't have: runtime arity reflection (fn.length) and
recursive conditional types. FxDart instead declares one extension per
arity (2–5), all exposing the same curried getter, and lets
the compiler pick the right one from the function's static type.
The arity dispatch FxTS does at runtime happens at compile time — and the
result is fully typed, with zero casts: add.curried(1)
is an int Function(int).
.uncurried is the inverse: it flattens a chain of unary
functions back into one multi-argument function. When a chain is nested
deeper than two levels, the deepest matching arity wins; apply an
extension explicitly (Uncurry2(f).uncurried) to flatten
fewer levels. The full design story — including why the getter is named
curried and not curry — is in
WHY_CURRIED.md.
Demo 1 · Basics
Demo 2 · Partial application in a pipeline
A curried binary function slots straight into map — no
wrapper closure needed:
Demo 3 · Round trip with uncurried
Hand-written curried closures flatten back to the data-first shape, and
curried / uncurried are exact inverses:
Try it yourself
Exercise: use .curried to build a clampTo100
function from clamp below, then map it over the list.
add(1, 2)(3) has no equivalent. Named parameters
and values typed as bare Function don't match the extensions;
write a closure there. Optional positional parameters do match,
but the optional slot becomes required in the chain. The deprecated
top-level curry stub remains only to steer FxTS migrations
here.