Currying
Currying turns a function of several arguments into a chain of functions of one argument each: becomes . The two forms are in one-to-one correspondence, which in mathematics is the exponential law . In OCaml and Haskell every function is curried, so partial application, supplying only some of a function's arguments to get a function of the rest, needs no special syntax.
Overview
A function of two arguments can be seen as a function that takes the first argument and returns a function waiting for the second. That is how OCaml treats every multi-argument function: int -> int -> int means int -> (int -> int), because the arrow associates to the right, and add 1 2 means (add 1) 2, because application associates to the left. The compiler's inferred types show it:
Curried and uncurried functions, and the conversions between them.
let curry f a b = f (a, b)let uncurry f (a, b) = f a blet add a b = a + blet add_pair (a, b) = a + blet increment = add 1let add3 a b c = a + b + clet add3_partial = add3 1 2
What ocamlc -i infers.
val curry : ('a * 'b -> 'c) -> 'a -> 'b -> 'cval uncurry : ('a -> 'b -> 'c) -> 'a * 'b -> 'cval add : int -> int -> intval add_pair : int * int -> intval increment : int -> intval add3 : int -> int -> int -> intval add3_partial : int -> int
add 1 is a complete value of type int -> int, and add3 1 2 of type int -> int. The tupled add_pair has to be given both components at once.
Definition
The two are inverses, and , so they give a bijection between the two function spaces. The same construction repeats for more arguments: a function of arguments becomes nested functions of one argument.
Partial application
Partial application is supplying fewer arguments than a function takes and getting a function of the remaining ones. It is related to currying but not the same thing: currying changes the type of a function, and partial application uses a curried function. Languages without curried functions provide it separately, for example Python's functools.partial and C++'s std::bind_front.
Partial application with positional, labelled and optional arguments.
let add a b = a + blet increment = add 1(* Partial application makes small functions out of general ones. *)let scaled = List.map (( * ) 10) [ 1; 2; 3 ]let evens = List.filter (fun n -> n mod 2 = 0)(* Labelled arguments can be supplied in any order, and partially. *)let rectangle ~width ~height = width * heightlet tall = rectangle ~height:10 (* still waiting for ~width *)(* An optional argument is erased once a positional argument after it is given. *)let greet ?(greeting = "Hello") name = greeting ^ ", " ^ name
Running it.
increment 41 -> 42List.map (( * ) 10) [1;2;3] -> [10; 20; 30]evens [1; 2; 3; 4] -> [2; 4]tall ~width:3 -> 30greet "Ada", greet ~greeting:"Hi" "Ada" -> Hello, Ada | Hi, Ada
OCaml's labelled arguments can be supplied in any order, so a function can be partially applied to any subset of them: rectangle ~height:10 is a function waiting for ~width. An optional argument is filled with its default once a positional argument that follows it is supplied, which is why optional arguments are written before at least one positional one[8].
Mathematics
The exponential law
Write for the set of functions from to . Currying is the bijection
which for finite sets is the law of exponents: . With booleans there are functions of each kind, and currying pairs them up exactly:
Every function bool * bool -> bool, curried, and checked against the original.
(* Every function bool * bool -> bool, as its table of four outputs. *)let inputs = [ (false, false); (false, true); (true, false); (true, true) ]let all_uncurried =List.init 16 (fun bits -> fun (a, b) ->let i = (if a then 2 else 0) + if b then 1 else 0 inbits land (1 lsl i) <> 0)let curry f a b = f (a, b)let uncurry f (a, b) = f a b(* Two functions bool -> bool -> bool are equal if they agree everywhere. *)let table_c g = List.map (fun (a, b) -> g a b) inputslet table_u f = List.map f inputs
Running it.
functions bool * bool -> bool : 16distinct curried images : 16uncurry (curry f) = f for all of them : true
Cartesian closed categories
In category theory, a category with finite products has exponentials when for every pair of objects there is an object with an evaluation arrow , such that every factors through it uniquely:
is the curried form of , and the uniqueness says the correspondence is bijective. Equivalently, there is an isomorphism natural in and , which makes left adjoint to :
A category with finite products and all exponentials is cartesian closed. Types and functions form one, and the simply typed λ-calculus is its internal language: typed λ-terms and arrows of cartesian closed categories correspond[6][5].
Logic
Under the Curry–Howard correspondence, where types are propositions and programs are proofs, currying is the logical equivalence called exportation:
and curry and uncurry, read as proofs, are the two directions.
In programming languages
In the λ-calculus every function takes one argument, and is shorthand for . ML, OCaml and Haskell inherit this: functions are curried by default, and a tuple argument is the exception, used when the arguments belong together.
Curried functions do not make calls slower. Compilers record each function's arity, a call that supplies every argument goes directly to the function's code, and only a partial application allocates a closure to hold the arguments given so far. Marlow and Peyton Jones compared the two ways of implementing this, push/enter and eval/apply[7].
Elsewhere currying is by hand. In JavaScript a curried function is a chain of arrow functions, a => b => a + b. Scala allows several parameter lists, def add(a: Int)(b: Int), each of which can be supplied separately.
History
Frege used the reduction of functions of several arguments to functions of one in 1893[1], and Schönfinkel made it systematic in 1924 in his work on combinatory logic[2]. Curry used it throughout combinatory logic[3], and the name currying is usually credited to Strachey, who used it in lecture notes in 1967[4]. Schönfinkelisation has been proposed as the more accurate name.
see also
- ClosureA closure is a function value together with the environment in which it was created: the bindings of the free variables its body refers to. Closures are what make functions first-class values in a lexically scoped language. Compilers implement them by closure conversion, which turns each function into a code pointer paired with a record of captured values.
- SKI combinatorsThree combinators, S x y z = x z (y z), K x y = x and I x = x, from which every closed lambda term can be built by application alone, with no variables. I is redundant, since S K K x = x. The translation from lambda terms is called bracket abstraction.
- Church encodingChurch encoding represents data in the pure lambda calculus, which has only functions, by functions: a natural number n is the function that applies its argument n times, a boolean is a function choosing between two alternatives, and a pair is a function waiting for a selector. In general a value is represented by its own fold. Arithmetic, logic and data structures all become lambda terms, which is how the lambda calculus was shown to express every computable function; in typed form the encoding needs polymorphism, as in System F.
- Algebraic data typeAn algebraic data type is a type built from sums, where a value is one of several alternatives, and products, where a value has several components at once, possibly recursively. The name comes from counting: the number of values of a sum is the sum of the counts, and of a product their product, so types obey the laws of algebra. Values are taken apart by pattern matching, which the compiler checks for missing cases.
further reading
- [1]G. Frege, Grundgesetze der Arithmetik, Vol. I, Jena (1893).
- [2]M. Schönfinkel, “Über die Bausteine der mathematischen Logik”, Mathematische Annalen 92 (1924).
- [3]H. B. Curry, R. Feys, Combinatory Logic, Vol. I, North-Holland (1958).
- [4]C. Strachey, “Fundamental concepts in programming languages”, lecture notes (1967); Higher-Order and Symbolic Computation 13 (2000).
- [5]S. Mac Lane, Categories for the Working Mathematician, ch. IV, Springer (2nd ed., 1998).
- [6]J. Lambek, P. J. Scott, Introduction to Higher Order Categorical Logic, Cambridge University Press (1986).
- [7]S. Marlow, S. Peyton Jones, “Making a fast curry: push/enter vs. eval/apply for higher-order languages”, Journal of Functional Programming 16 (2006).
- [8]J. Garrigue, “Labeled and optional arguments for Objective Caml”, JSSST Workshop on Programming and Programming Languages (2001).
last updated