In language design, there is a tradeoff to make between implicit folding and implicit currying.
Let’s take the + function as an example: it is a function which takes 2 arguments and returns 1 result. What if we passed 3 or more arguments to it instead? What if we passed less than 2? In principle, it doesn’t mean anything. So we have 3 options:
1- If the user passes more or less than 2 arguments, raise an error. We have left operand an right operand. More or less than 2 arguments has no meaning, what do you even mean by that?
This is the path that Python takes:
>>> from operator import add >>> add(2,3) 5 >>> add(1,2,3) # oops! expected 2 arguments, got 3 >>> add(1) # oops! expected 2 arguments, got 1
2- If the user passes any number of arguments, add them all. Thus, you are performing an implicit fold.
This is the path that Lisp takes:
(+ 1 2 3) ; => 6 (+ 1) ; => 1
3- If the user passes less than the required arguments (2 in this case), partially apply the function to the supplied arguments. Thus, the + is implicitly curried.
This is the path that Haskell takes:
(+ 7) -- a function of 1 argument that adds 7 to the number you pass as argument
PROS & CONS
By defining the meaning of passing fewer/more than required number of arguments to a function, you are able to squeeze more meaning into your language, potentially resulting in a more concise and small language. By choosing option number 1 (raising an error), you miss that opportunity. A pro might be that eventually there is going to be a newbie that passes a wrong number of arguments by accident, and you want to let them know.
A pro of option 2 (implicit folding) is that you can pass any number of arguments and it always has a meaning. On the other hand, option number 3 (implicit currying) only has a meaning if you pass lower than required arguments (if you pass more it is an error).
For functions like + and *, this is very useful, you will use folding with these functions a lot. In general, it is useful for functions of signature a→b→a (with + and * being a particular case, with signatures a→a→a ). As a cons, not all functions have these signatures and it is unclear how we should generalize folding to these other functions.
Option 3 is easily generalizable to any function, unlike option 2. If you think in terms of functions and function composition (instead of function application), this will be very handy, you will be creating partially applied functions all the time.
This won’t be a substitute for general partial application (what if you wanted to partially apply a function on its second argument?), but still will cover many use cases.
My personal favorite is option 3, implicit currying. What about you?