News for hackers. Stuff that matters.
Re:Currying by whilenot-dev on Sunday April 07, 2024 @03:53AM (#39959055)
I don't read it that way, no. Currying is a process to transform a function that takes multiple arguments into higher order functions that take one argument at a time to enable partial application (as written in the article). The partial application of a function is a different transformation of a function.

Some languages provide partial application without currying a function - JavaScript has bind, Python has functools.partial etc.

Re:Currying by kerkeslager on Sunday April 07, 2024 @04:44AM (#39959339)
Okay, I understand what you're saying, and you're right, but you're missing my point and doubling down on the same mistake again.

Language is inherently imprecise and communication is never perfect. When people say something, it's rude to assume they are wrong or don't understand something because they don't say it exactly the way you would have said it. This is extremely common in technical communication and it's extremely counterproductive.

I'm suggesting that you could be a better reader by trying to understand what people are trying to say even if they don't communicate it exactly the way you want them to.

For example, no one in this comment chain is confused about what currying or partial application are, so it's a bit rude that you've assumed people are confused because you didn't take the time to figure out what people were trying to communicate. Instead, because people didn't say things exactly the way you would have said it, you jumped in with corrections.

If you take a step back and resist the urge to correct people, can you understand how "Currying is a subset of partial application" is true?

Re:Currying by whilenot-dev on Sunday April 07, 2024 @05:13AM (#39959477)
> no one in this comment chain is confused about what currying or partial application are

I can't agree here either... I know it from my own experience when i first learned about currying and partial application.

Re:Currying by kerkeslager on Sunday April 07, 2024 @06:22AM (#39959782)
It does not appear to me that skybrian is first learning about currying and partial application, and I'm not first learning about currying or partial application in this thread either.

Your play at humility that you didn't understand currying and partial application in the past kinda falls flat if you then go on to less-humbly assume that everyone else in the conversation is stuck where you once were.

Re:Currying by electrondood on Tuesday April 09, 2024 @03:56AM (#39977092)
You seem to be reacting to your own assumption that the original response was making an assumption.

I understood it instead to be generalizing to a related concept, and inferred no condescension, FWIW.

Re:Currying by whilenot-dev on Sunday April 07, 2024 @05:03AM (#39959414)
> ...can you understand how "Currying is a subset of partial application" is true?

It isn't true and i can understand why someone would make that statement. Currying and partial application both come from a functional mindset that treats functions as data, and like data also functions can be transformed.

Currying and partial application both satisfy a transformation depending on a desired context:

  - Currying "widens" a function "up" (as in you don't need to know all arguments beforehand in the same context anymore)
  - Partial application "narrows" a function "down" (as in arguments are contained within the context of the partially applied function)
"Currying is a subset of partial application" is true in the same sense as if "subtraction is a subset of addition". Sure, you can subtract negative values to have addition and add negative values to have subtraction, but that can't be your point, is it?

> If you take a step back and resist the urge to correct people...

Please keep it on topic.

Re:Currying by kerkeslager on Sunday April 07, 2024 @05:48AM (#39959651)
> It isn't true and i can understand why someone would make that statement

It is true, and you are smart enough to understand it if you stop assuming you're the only one who understands the topic. I'm specifically sticking with the wording "Currying is a subset of partial application" to make the point that you can understand what someone is trying to say even if they don't say it exactly the way you would like them to say it.

> - Currying "widens" a function "up" (as in you don't need to know all arguments beforehand in the same context anymore) > - Partial application "narrows" a function "down" (as in arguments are contained within the context of the partially applied function)

So you're saying that I'm "widening" the function "up" when I do:

    increment = add 1
    invert = div 1
...? But I'm "narrowing" the function "down" when I do:

    increment = (\x -> add 1 x)
    halve = (\x -> div x 2)
...?

When I curry `add` above, isn't the argument 1 contained within the context of the partially applied function?

When I partially apply `div` above, don't I no longer have to know all the arguments (i.e. I no longer need to know the denominator 2)?

It sure seems like this up/down wide/narrow wording you're fixated on isn't a particularly better descriptions of what's going on with currying and partial application.

It mean, maybe it's just my font, but the partial applications are a bit wider on my screen. ;P

> "Currying is a subset of partial application" is true in the same sense as if "subtraction is a subset of addition". Sure, you can subtract negative values to have addition and add negative values to have subtraction, but that can't be your point, is it?

I'm not sure I understand that analogy to say it's my point.

Are you saying you would behave condescendingly toward someone who said "subtraction is a subset of addition" too?

> Please keep it on topic.

The topic skybrian started was derailed when you decided to "correct" him because you didn't make any effort to understand what he was trying to say. Your behavior is the topic now because your behavior became a problem.

Re:Currying by whilenot-dev on Sunday April 07, 2024 @06:19AM (#39959768)
Neither of your examples does curry a function. The first one partially applies it (the Haskell way), the second one wraps the partial application in a redundant lambda (Haskell again). I think that's where the confusion is, let me also try to use the Haskell syntax...

This is an add function with two arguments:

  add :: (Int, Int) -> Int
  add (x, y) = x + y
At the moment it can not be partially applied, so let's curry it:

  -- addCurr :: Int -> Int -> Int
  addCurr = curry add
Now let's partially apply it for an increment function:

  -- increment :: Int -> Int
  increment = addCurr 1
> When I curry `add` above, isn't the argument 1 contained within the context of the partially applied function?

You didn't curry it, you partially applied it. This was possible, because your function add was already curried.

Re:Currying by kerkeslager on Sunday April 07, 2024 @06:47AM (#39959906)
Okay, that's a fair critique, let it not be said I can't admit when I'm wrong. I shouldn't have used `curry` as a verb there, as my point was about the concept of currying rather than the specific curry function.

My mistake there doesn't negate my larger point, but I've gotta go touch grass.

Re:Currying by kerkeslager on Tuesday April 09, 2024 @01:24AM (#39976372)
Coming back to this having spent a wonderful day outdoors.

Okay, writing this in Python because a) it's been a while since I wrote Haskell, b) it will let other readers read the code more easily, and c) Python clearly denotes what a partial is by having a `partial` function:

    from inspect import signature
    from functools import partial

    def curry(f, parameters=None):
        if parameters is None:
            parameters = list(signature(f).parameters.keys())

        if len(parameters) == 0:
            return f

        head = parameters[0]
        tail = parameters[1:]

        # I draw your attention to this line
        return lambda p: curry(partial(f, **{head: p}), tail)

    def divide(a, b, c):
        return a / b / c

    curried_divide = curry(divide)

    # prints "3"
    print(curried_divide(30)(5)(2)())
So... curry can be implemented in terms of partial applications, no?
Re:Currying by whilenot-dev on Tuesday April 09, 2024 @07:43AM (#39978415)
I'm happy that you spent a wonderful day outdoors!

Do you think that makes your statement "Currying is a subset of partial application" (and doubling down on that) any more true?

After all, you can implement subtraction with just the help of addition and multiplication:

  add :: Int -> Int -> Int
  add a b = a + b

  mult :: Int -> Int -> Int
  mult a b = a * b

  sub :: Int -> Int -> Int
  sub a b = add a (mult (-1) b)
So, does that make "subtraction is a subset of addition" a true statement?
Re:Currying by kerkeslager on Tuesday April 09, 2024 @11:36AM (#39980573)
Yes. Why not? Would you be confused about what someone meant if they said that statement?

My critique of your original post is that you're treating English like it's a computer language where words mean very specific things. But the reality is that English is a cobbled-together bunch of words with imprecise meanings that arise from common usage. Let me reiterate: usage determines meaning, not the other way around.

You're approaching this conversation with your own preconceived notions about what the words mean and trying to force your preconceived notions onto everyone else instead of trying to understand what the other person means. It's a rude way to treat people trying to communicate with you.

I mean, it's clear that you understand the idea because you're coming up with examples that show that you understand it. Communication was successful. There's no problem with the communication. The problem is that you decided, after communication was successful, to force your preferred usage of the words on other people.

This is an extremely common interpersonal mistake that technical people make because unlike English, computer languages have very specific, objective meanings. But expecting that same objective specificity from humans speaking English isn't realistic, kind, or polite. It's one of the main reasons technical people are widely perceived as socially inept. Behaving like this hurts our careers, friendships, and romantic relationships. Doing this on HN is just a minor annoyance to everyone else, but if you do this in your life as a whole, the person you're harming most is yourself, because you're making it a pain in the ass to communicate with you.

I'm asking you to be a better reader and listener.

And look, maybe you can get skybrian or me to change the way we communicate to suit your preferences, but why? Nothing is gained. And if you spend your life trying to force people to communicate a certain way instead of trying to understand people, it's just going to be an endless war, where the only meaningful result you'll achieve is that it's harder for people to communicate with you. Is that what you want for yourself?

If you'd approached this from the perspective of "hey I think people would understand you better if you said it this other way", that would be fine. I think it's great to improve communication, and it's both up to speaker/writer and listener/reader to meet in the middle: both sides of this interaction can improve. But that's a pretty big difference between coming at someone like "you're wrong".

Re:Currying by whilenot-dev on Tuesday April 09, 2024 @12:38PM (#39981194)
> Yes. Why not?

...because I think you'd write mathematical history if you can prove it?

> You're approaching this conversation with your own preconceived notions about what the words mean...

Peak meta, yes!

> ...to force your preferred usage of the words on other people.

Listen, currying is a defined term[0], as is partial application[1]. Those are primarily mathematic definitions, and your choice of words "...is a subset of..." is also stemming from a rather mathematical terminology if you'd ask me. Therefor its interpretation will primarily be itching logical intelligence.

Currying can be implemented by making use of a partial application, and partial application can be implemented by making use of currying a function. Neither one is a subset of the other and both are higher-order functions.

It was your choice of words with which you formed your statements, and no, I'm not going to discuss visual, linguistic, interpersonal, intrapersonal or naturalistic understandings with you on Hacker News about your intentions, I'm truly sorry. Your point "about the concept of currying" doesn't exist (yet AFAIK), feel free to imagine whatever higher concept you desire.

Even the confusion between currying and partial application is well known[2][3] and also documented on Wikipedia - you put in a prime example out of the confusion, thank you. You still double down on false statements, fine, use your languages however you want and feel free to interpret "I think you confuse currying with partial application." as a behavioral problem. It's truly amazing.

[0]: https://en.wikipedia.org/wiki/Currying

[1]: https://en.wikipedia.org/wiki/Partial_application

[2]: http://lambda-the-ultimate.org/node/2266

[3]: https://www.uncarved.com/articles/not-currying/

Re:Currying by kerkeslager on Wednesday April 10, 2024 @12:56AM (#39987098)
> ...because I think you'd write mathematical history if you can prove it?

No, because this is an informal conversation not a mathematical paper.

Clearly you understand what is meant if someone says that subtraction is a subset of addition. You also clearly understand they're not saying it as a statement of proof.

If you can understand someone well enough to correct their usage of words, you understand them well enough that they communicated successfully. So why create a problem?

> Listen, currying is a defined term[0], as is partial application[1]. Those are primarily mathematic definitions, and your choice of words "...is a subset of..." is also stemming from a rather mathematical terminology if you'd ask me. Therefor its interpretation will primarily be itching logical intelligence.

Yes, I'm well aware, I just don't care. People use words outside their dictionary definitions all the time and if we understand it, it doesn't matter.

Perhaps you should look up the word pedant? Dictionary authors are well aware of the pitfalls of relying on definitions as prescription rather than description.

> I'm not going to discuss visual, linguistic, interpersonal, intrapersonal or naturalistic understandings with you on Hacker News about your intentions,

Well, that's your prerogative, but I'll note that you haven't said anything interesting about currying because you keep assuming your audience knows less than they do. Learning to listen at an adult level would help you to have more interesting technical discussions, too.

Re:Currying by threatofrain on Sunday April 07, 2024 @05:15AM (#39959487)
I thought it was somewhat the reverse — that the original motivation was to simulate multi-arity functions in a setting that only allows unary functions.
Re:Currying by bPspGiJT8Y on Sunday April 07, 2024 @06:33AM (#39959831)
I don't really understand the distinction between "multi-arity" and "unary" functions. In my mental model, all functions are unary, it's just that in "traditional", non-FP languages it's more common to pack arguments into tuples. That is `(a, b, c) => ...` in JS is a unary function which takes a tuple of 3 items. But the thing is, FP has tuples too (and in Haskell, with pretty much the same syntax), it's just that most of the time arguments aren't packed into tuples.

So could you elaborate to me where the distinction lies here and why is there a need to "simulate" things?

Re:Currying by jraph on Sunday April 07, 2024 @06:47AM (#39959910)
Say you are dealing with a callback mechanism that takes a function and (only) one value to pass:

   function c(f, v) { ... f(v) ... }

But what you actually need this callback mechanism to call is a function that takes two arguments. No default values.

    function f2(a, b) { ... }
There's no way in js that c is going to call f2 and set its b parameter to something. You can't set v to be a tuple so b will be filled:

    c(f2, "value") => b will be undefined.

    c(f2, [1, 2]) => a will be set to [1, 2].
you need to wrap f2 for this when calling c:

    function wrapf2(b) { return f2("fixed a", b) }
Or you can make c deconstruct v, or use apply:

    function c(f, v) { ... f(...v) ...  }
    function c(f, v) { ... f.apply(null, v) ...  }
but then v always needs to be an array:

    c(f, [1])
    c(f, [1, 2])

    c(f, 1) // fails
This is why in Javascript, multi-arity is different from unary with tuples. JS doesn't have tuples as a primitive / first-class type anyway. In some math notations we don't make the difference, but in most programming languages there's a distinction. Your model where functions are always unary but can take tuples, and (v) is the same as v, is correct (and useful when the distinction doesn't matter and is just annoying to deal with), but doesn't match the way many programming languages actually work. I believe even in most functional programming languages, (v) is different from v, you also said it.

In assembly, different parameters are in fully separate registers or stack entries. Interestingly, you could imagine representing tuples as C structs (that can have only one member) and always pass structs, and passing a one-member struct will actually have the exact same effect as passing a value of a primitive type.