The usual implementation of fold/reduce takes a separate seed argument (as does clojure, optionally!), which IMO is far more sensible than having the same function do two completely separate things depending on the number of arguments.
How would you write a function parameter that takes two arguments, whose type is determined by the seed argument?
Also, with reduce, the return value of the function can determine what the type of the input arguments should be. For example if you pass in a `(fn (x y) (list x y))`, you end up with:
> (reduce (fn (x y)
(list x y))
(list "a" "b" "c" "d"))
("a" ("b" ("c" "d")))
Let's throw in a print statement to print out the `y` parameter:
So `y` starts out as a string, then a list of strings, then a list whose first element is a string and the second element is a list of strings, and so on.
I'm not sure what the type of that function would even look like. And if there's no way to express something as simple as `reduce` without resorting to `f: (x: Any, y: Any) -> Any`, are we certain it's good design?
And this is the other thing I like about the haskell/ML collection of languages. The description you gave above is extremely concise and direct. If you're familiar with the language being used it's a very efficient form of communication.
I've noticed that working in languages of that family gives you a vocabulary to talk about things that previously would have been very wordy to discuss.
Languages with these types of type features provide easy abstractions to illuminate structure and patterns begin discussing new ideas that previously would've been considered on off code.
FWIW, this can be inferred fully automatically. Type
let pair = fun x -> fun y -> { _0 = x; _1 = y }
let rec reduce = fun init -> fun combine -> fun xs ->
match xs with
[] -> init
| x :: rest -> reduce (combine x init) combine rest
let test = reduce 0 pair [1; 2; 3; 4]
`O` would be whatever the type of the reducer is, so for `list` in the lisp you're using (is it Clojure? The function params look wrong) has a type signature `(A, B?, ...Z?) -> A | List(A, B, ...Z)`.
So the transducer in this case would have the type `List(A, B?, ...Z?) -> A | List(A, B | List(B, ...etc))`
It's not three different types, but it is necessarily recursive, which seems tricky.