In mathematics and computer science, currying is the technique of translating a function that takes multiple arguments into a sequence of families of functions, each taking a single argument.
In the prototypical example, one begins with a function
f:(X x Y)\toZ
X
Y,
Z.
fx:Y\toZ.
x
X,
fx.
In this example,
curry
f
x
fx.
f
(X x Y)\toZ.
fx
Y\toZ.
x
fx
X\to[Y\toZ].
curry
curry:[(X x Y)\toZ]\to(X\to[Y\toZ]).
Currying is related to, but not the same as, partial application.[1] The example above can be used to illustrate partial application; it is quite similar. Partial application is the function
apply
f
x
fx.
apply:([(X x Y)\toZ] x X)\to[Y\toZ].
The currying of a function with more than two arguments can be defined by induction.
Currying is useful in both practical and theoretical settings. In functional programming languages, and many others, it provides a way of automatically managing how arguments are passed to functions and exceptions. In theoretical computer science, it provides a way to study functions with multiple arguments in simpler theoretical models which provide only one argument. The most general setting for the strict notion of currying and uncurrying is in the closed monoidal categories, which underpins a vast generalization of the Curry–Howard correspondence of proofs and programs to a correspondence with many other structures, including quantum mechanics, cobordisms and string theory.
The concept of currying was introduced by Gottlob Frege,[2] [3] developed by Moses Schönfinkel,[4] [3] [5] [6] [7] [8] and further developed by Haskell Curry.[9] [10]
f
g
f'
f
g
f
g
Currying provides a way for working with functions that take multiple arguments, and using them in frameworks where functions might take only one argument. For example, some analytical techniques can only be applied to functions with a single argument. Practical functions frequently take more arguments than this. Frege showed that it was sufficient to provide solutions for the single argument case, as it was possible to transform a function with multiple arguments into a chain of single-argument functions instead. This transformation is the process now known as currying.[11] All "ordinary" functions that might typically be encountered in mathematical analysis or in computer programming can be curried. However, there are categories in which currying is not possible; the most general categories which allow currying are the closed monoidal categories.
Some programming languages almost always use curried functions to achieve multiple arguments; notable examples are ML and Haskell, where in both cases all functions have exactly one argument. This property is inherited from lambda calculus, where multi-argument functions are usually represented in curried form.
Currying is related to, but not the same as partial application. In practice, the programming technique of closures can be used to perform partial application and a kind of currying, by hiding arguments in an environment that travels with the curried function.
The "Curry" in "Currying" is a reference to logician Haskell Curry, who used the concept extensively, but Moses Schönfinkel had the idea six years before Curry.[12] The alternative name "Schönfinkelisation" has been proposed.[13] In the mathematical context, the principle can be traced back to work in 1893 by Frege.[2] [3]
The originator of the word "currying" is not clear. David Turner says the word was coined by Christopher Strachey in his 1967 lecture notes Fundamental Concepts in Programming Languages,[14] but that source introduces the concept as "a device originated by Schönfinkel", and the term "currying" is not used, while Curry is mentioned later in the context of higher-order functions.[5] John C. Reynolds defined "currying" in a 1972 paper, but did not claim to have coined the term.[6]
Currying is most easily understood by starting with an informal definition, which can then be molded to fit many different domains. First, there is some notation to be established. The notation
X\toY
X
Y
f
f\colonX\toY
X x Y
X
Y
X
Y
X
Y
Given a function
f\colon(X x Y)\toZ
currying constructs a new function
g\colonX\to(Y\toZ)
That is,
g
X
Y\toZ
g(x)(y)=f(x,y)
for
x
X
y
Y
curry(f)=g.
Uncurrying is the reverse transformation, and is most easily understood in terms of its right adjoint, the function \operatorname{apply}.
In set theory, the notation
YX
X
Y
AB x
B x C
A
(AC)B
B
C
A
AB x \cong(AC)B
Indeed, it is this natural bijection that justifies the exponential notation for the set of functions. As is the case in all instances of currying, the formula above describes an adjoint pair of functors: for every fixed set
C
B\mapstoB x C
A\mapstoAC
YX
In the theory of function spaces, such as in functional analysis or homotopy theory, one is commonly interested in continuous functions between topological spaces. One writes
Hom(X,Y)
X
Y
YX
curry
curry:Hom(X x Y,Z)\toHom(X,Hom(Y,Z)),
while uncurrying is the inverse map. If the set
YX
X
Y
Y
curry:ZX x \to(ZY)X
is a homeomorphism. This is also the case when
X
Y
YX
One useful corollary is that a function is continuous if and only if its curried form is continuous. Another important result is that the application map, usually called "evaluation" in this context, is continuous (note that eval is a strictly different concept in computer science.) That is,
\begin{align}&&eval:YX x X\toY\\ &&(f,x)\mapstof(x)\end{align}
is continuous when
YX
Y
X
I
ZI x \cong(ZY)I
Y
Z
ZY
In algebraic topology, currying serves as an example of Eckmann–Hilton duality, and, as such, plays an important role in a variety of different settings. For example, loop space is adjoint to reduced suspensions; this is commonly written as
[\SigmaX,Z] ≈ eq[X,\OmegaZ]
[A,B]
A → B
\SigmaA
\OmegaA
\SigmaX
X
X
Z
X
\OmegaZ
curry
The duality between the mapping cone and the mapping fiber (cofibration and fibration)[15] can be understood as a form of currying, which in turn leads to the duality of the long exact and coexact Puppe sequences.
In homological algebra, the relationship between currying and uncurrying is known as tensor-hom adjunction. Here, an interesting twist arises: the Hom functor and the tensor product functor might not lift to an exact sequence; this leads to the definition of the Ext functor and the Tor functor.
In order theory, that is, the theory of lattices of partially ordered sets,
curry
The notion of continuity makes its appearance in homotopy type theory, where, roughly speaking, two computer programs can be considered to be homotopic, i.e. compute the same results, if they can be "continuously" refactored from one to the other.
In theoretical computer science, currying provides a way to study functions with multiple arguments in very simple theoretical models, such as the lambda calculus, in which functions only take a single argument. Consider a function
f(x,y)
(X x Y)\toZ
X
Y
Z
curry(f)=λx.(λy.(f(x,y)))
where
λ
(X x Y)\toZ
curry:((X x Y)\toZ)\to(X\to(Y\toZ))
The → operator is often considered right-associative, so the curried function type
X\to(Y\toZ)
X\toY\toZ
f(x,y)
((curry(f) x) y)=curry(f) x y
That is, the parenthesis are not required to disambiguate the order of the application.
Curried functions may be used in any programming language that supports closures; however, uncurried functions are generally preferred for efficiency reasons, since the overhead of partial application and closure creation can then be avoided for most function calls.
In type theory, the general idea of a type system in computer science is formalized into a specific algebra of types. For example, when writing
f\colonX\toY
X
Y
\to
X x Y
x
The type-theoretical approach is expressed in programming languages such as ML and the languages derived from and inspired by it: CaML, Haskell and F#.
The type-theoretical approach provides a natural complement to the language of category theory, as discussed below. This is because categories, and specifically, monoidal categories, have an internal language, with simply-typed lambda calculus being the most prominent example of such a language. It is important in this context, because it can be built from a single type constructor, the arrow type. Currying then endows the language with a natural product type. The correspondence between objects in categories and types then allows programming languages to be re-interpreted as logics (via Curry–Howard correspondence), and as other types of mathematical systems, as explored further, below.
Under the Curry–Howard correspondence, the existence of currying and uncurrying is equivalent to the logical theorem
((A\landB)\toC)\Leftrightarrow(A\to(B\toC))
QP
P\toQ
\negP\lorQ
f\colon(X x Y)\toZ
g\colonX\toZY
This generalizes to a broader result in closed monoidal categories: Currying is the statement that the tensor product and the internal Hom are adjoint functors; that is, for every object
B
Hom(A ⊗ B,C)\congHom(A,B ⇒ C).
Here, Hom denotes the (external) Hom-functor of all morphisms in the category, while
B ⇒ C
B ⇒ C
CB
Currying can break down in one of two ways. One is if a category is not closed, and thus lacks an internal hom functor (possibly because there is more than one choice for such a functor). Another way is if it is not monoidal, and thus lacks a product (that is, lacks a way of writing down pairs of objects). Categories that do have both products and internal homs are exactly the closed monoidal categories.
The setting of cartesian closed categories is sufficient for the discussion of classical logic; the more general setting of closed monoidal categories is suitable for quantum computation.[22]
The difference between these two is that the product for cartesian categories (such as the category of sets, complete partial orders or Heyting algebras) is just the Cartesian product; it is interpreted as an ordered pair of items (or a list). Simply typed lambda calculus is the internal language of cartesian closed categories; and it is for this reason that pairs and lists are the primary types in the type theory of LISP, Scheme and many functional programming languages.
By contrast, the product for monoidal categories (such as Hilbert space and the vector spaces of functional analysis) is the tensor product. The internal language of such categories is linear logic, a form of quantum logic; the corresponding type system is the linear type system. Such categories are suitable for describing entangled quantum states, and, more generally, allow a vast generalization of the Curry–Howard correspondence to quantum mechanics, to cobordisms in algebraic topology, and to string theory.[23] The linear type system, and linear logic are useful for describing synchronization primitives, such as mutual exclusion locks, and the operation of vending machines.
See main article: article and Partial application. Currying and partial function application are often conflated.[24] One of the significant differences between the two is that a call to a partially applied function returns the result right away, not another function down the currying chain; this distinction can be illustrated clearly for functions whose arity is greater than two.[25]
Given a function of type
f\colon(X x Y x Z)\toN
curry(f)\colonX\to(Y\to(Z\toN))
f(1,2,3)
fcurried(1)(2)(3)
fcurried(1)
In contrast, partial function application refers to the process of fixing a number of arguments to a function, producing another function of smaller arity. Given the definition of
f
partial(f)\colon(Y x Z)\toN
fpartial(2,3)
Intuitively, partial function application says "if you fix the first argument of the function, you get a function of the remaining arguments". For example, if function div stands for the division operation x/y, then div with the parameter x fixed at 1 (i.e., div 1) is another function: the same as the function inv that returns the multiplicative inverse of its argument, defined by inv(y) = 1/y.
The practical motivation for partial application is that very often the functions obtained by supplying some but not all of the arguments to a function are useful; for example, many languages have a function or operator similar to plus_one
. Partial application makes it easy to define these functions, for example by creating a function that represents the addition operator with 1 bound as its first argument.
Partial application can be seen as evaluating a curried function at a fixed point, e.g. given
f\colon(X x Y x Z)\toN
a\inX
curry(partial(f)a)(y)(z)=curry(f)(a)(y)(z)
partial(f)a=curry1(f)(a)
curry1
Thus, partial application is reduced to a curried function at a fixed point. Further, a curried function at a fixed point is (trivially), a partial application. For further evidence, note that, given any function
f(x,y)
g(y,x)
g(y,x)=f(x,y)
So, a partial application can be defined as the objective result of a single application of the curry operator on some ordering of the inputs of some function.
Republished as Reynolds . John C. . John C. Reynolds . 1998 . Definitional Interpreters for Higher-Order Programming Languages . Higher-Order and Symbolic Computation . Kluwer Academic Publishers . Boston . 11 . 4 . 363–397 . 10.1023/A:1010027404223 . 13 . Syracuse University: College of Engineering and Computer Science - Former Departments, Centers, Institutes and Projects.