I understand the difference between partial function application and a curried function (f(X x Y x Z) -> N
vs f(X -> (Y -> (Z -> N)))
), but I do not see what the consequence of this difference is when developing software.
2 Answers
Originally, currying was to simplify analysis, rather than a practical programming technique; in lambda calculus, all functions are unary. Currying is often used at the language level for a similar reason: simplifying the computational model.
Partial application is used when a named, useful function can be implemented in terms of another, more general function simply by fixing an argument.
They remain distinct forms, involving different parts of computation. Consider:
x=>y=>z=>f(x,y)
(y,z)=>f(0,y,z)
Note that a curried function doesn't have any values bound to arguments and takes the arguments in a specific order; once you curry a function, you don't curry the result and don't change the order that the function takes arguments (though you could uncurry and curry to do so). A partial function, in contrast, has values bound to arguments and can be further partially applied along any remaining argument.
Applying a curried function is close to partial application (you don't, after all, curry a function and leave it at that; at some point, you're going to apply it), which is where uses begin to cross over. When you do this, currying is only the first of two steps towards partial application.
I believe that your question can be rephrased as: why do languages have currying?
It is mostly a question of convenience:
In Ocaml, you could code
let sum3 x y z = x + y + z;;
let foo xx yy ll = List.map (sum3 xx yy) ll;;
In Scheme you'll need to explicitly make an anonymous function
(define (sum3 x y z) (+ x y z))
(define (foo xx yy ll) (map (lambda (zz) (sum3 xx yy zz)) ll))
Languages with partial applications & currying need practically to have an optimization to avoid creating partial closures everywhere; you don't want the implementation to always apply sum3
as if it was defined as
let sum3 x =
fun y ->
(fun z -> x + y + z)
that is, to allocate 2 intermediate closures when computing sum3 1 2 3
(understood and parsed as ((sum3 1) 2) 3
...). You want the sum to be computed immediately.