I'm biased here since the easy currying is by far my favourite feature in Haskell (it always bothers me that I have to explicitly create a lamba in Lisps) but the arguments in the article don't convince me, what with the synctactic overhead for the "tuple style".
lukev 9 minutes ago [-]
I'd got a step further and say that in business software, named parameters are preferable for all but the smallest functions.
Using curried OR tuple arg lists requires remembering the name of an argument by its position. This saves room on the screen but is mental overhead.
The fact is that arguments do always have names anyway and you always have to know what they are.
Thanks for sharing, interesting to see that people using functional languages in practice also experience the same issues. And they give some reasons I didn't think about.
leoc 5 minutes ago [-]
Right. Currying as the default means of passing arguments in functional languages is a gimmick, a hack in the derogatory sense. It's low-level and anti-declarative.
messe 23 minutes ago [-]
What benefit does drawing a distinction between parameter list and single-parameter tuple style bring?
I'm failing to see how they're not isomorphic.
Kambing 10 minutes ago [-]
They are isomorphic in the strong sense that their logical interpretations are identical. Applying Curry-Howard, a function type is an implication, so a curried function with type A -> B -> C is equivalent to an implication that says "If A, then if B, then C." Likewise, a tuple is a conjunction, so a non-curried function with type (A, B) -> C is equivalent to the logic statement (A /\ B) -> C, i.e., "If A and B then C." Both logical statements are equivalent, i.e., have the same truth tables.
However, as the article outlines, there are differences (both positive and negative) to using functions with these types. Curried functions allow for partial application, leading to elegant definitions, e.g., in Haskell, we can define a function that sums over lists as sum = foldl (+) 0 where we leave out foldl's final list argument, giving us a function expecting a list that performs the behavior we expect. However, this style of programming can lead to weird games and unweildy code because of the positional nature of curried functions, e.g., having to use function combinators such as Haskell's flip function (with type (A -> B -> C) -> B -> A -> C) to juggle arguments you do not want to fill to the end of the parameter list.
messe 4 minutes ago [-]
Please see my other comment below, and maybe re-read the article. I'm not asking what the difference is between curried and non-curried. The article draws a three way distinction, while I'm asking why two of them should be considered distinct, and not the pair you're referring to.
recursivecaveat 9 minutes ago [-]
Probably just that having parameter-lists as a specific special feature makes them distinct from tuple types. So you may end up with packing/unpacking features to convert between them, and a function being generic over its number of parameters is distinct from it being generic over its input types. On the other hand you can more easily do stuff like named args or default values.
emih 14 minutes ago [-]
That's a fair point, they are all isomorphic.
The distinction is mostly semantic so you could say they are the same. But I thought it makes sense to emphasize that the former is a feature of function types, and the latter is still technically single-parameter.
I suppose one real difference is that you cannot feed a tuple into a parameter list function. Like:
fn do_something(name: &str, age: u32) { ... }
let person = ("Alice", 40);
do_something(person); // doesn't compile
Pay08 19 minutes ago [-]
The tuple style can't be curried (in Haskell).
messe 16 minutes ago [-]
That's not what I'm talking about.
The article draws a three way distinction between curried style (à la Haskell), tuples and parameter list.
I'm talking about the distinction it claims exists between the latter two.
disconcision 3 minutes ago [-]
all three are isomorphic. but in some languages if you define a function via something like `function myFun(x: Int, y: Bool) = ...` and also have some value `let a: (Int, Bool) = (1, true)` it doesn't mean you can call `myFun(a)`. because a parameter list is treated by the language as a different kind of construct than a tuple.
Rendered at 14:06:35 GMT+0000 (Coordinated Universal Time) with Vercel.
Using curried OR tuple arg lists requires remembering the name of an argument by its position. This saves room on the screen but is mental overhead.
The fact is that arguments do always have names anyway and you always have to know what they are.
I'm failing to see how they're not isomorphic.
However, as the article outlines, there are differences (both positive and negative) to using functions with these types. Curried functions allow for partial application, leading to elegant definitions, e.g., in Haskell, we can define a function that sums over lists as sum = foldl (+) 0 where we leave out foldl's final list argument, giving us a function expecting a list that performs the behavior we expect. However, this style of programming can lead to weird games and unweildy code because of the positional nature of curried functions, e.g., having to use function combinators such as Haskell's flip function (with type (A -> B -> C) -> B -> A -> C) to juggle arguments you do not want to fill to the end of the parameter list.
The distinction is mostly semantic so you could say they are the same. But I thought it makes sense to emphasize that the former is a feature of function types, and the latter is still technically single-parameter.
I suppose one real difference is that you cannot feed a tuple into a parameter list function. Like:
fn do_something(name: &str, age: u32) { ... }
let person = ("Alice", 40);
do_something(person); // doesn't compile
The article draws a three way distinction between curried style (à la Haskell), tuples and parameter list.
I'm talking about the distinction it claims exists between the latter two.