0

✔||🤢 Commit or Vomit | function currying 🍛

 3 years ago
source link: https://dev.to/jmdejager/commit-or-vomit-function-currying-4m17
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Commit or Vomit (6 Part Series)

Function currying

Hard to put vomit and curry together in a title, but I had to ask 😁

I see this posted a lot on dev.to, function currying, but I find it not that readable myself TBH. What do you think?
And please tell me why 😊

// edit::
// It is about the concept of currying so changed to a 
// better way of writing
// I'll leave the first version at the bottom 
// for the comments that are already in!

const multiply = a => b => c => a*b*c
console.log(multiply(1)(2)(3)) // 6

// initial code block

function multiply(a) {
    return (b) => {
        return (c) => {
            return a * b * c
        }
    }
}
console.log(multiply(1)(2)(3)) // 6


Enter fullscreen modeExit fullscreen mode

function currying ✔||🤢?

❤: Commit (I'd commit something like this)
🏷: Vomit (we all know unicorns don't vomit)
🦄: Like your post please continue this series!

Let's vote! 😊

Photo by Jason Leung on Unsplash

Commit or Vomit (6 Part Series)

Discussion (22)

pic

CollapseExpand

Currying is confusing at first but incredibly useful in the right circumstances. Doing a lot of FP it's become the norm until a new starter joins and I have to explain it again, it's weird how gross things become normal.

Currying definitely looks less gross to me when you use braceless arrow functions though.

Also this example is technically not currying, it's higher order functions. Currying is where you have a function with n parameters, and wrap it in a function that can take 0-n parameters and returns a new function until it has all n parameters. For example:

const multiply = curry((a, b, c) => {
  return a * b * c
})

multiply(1, 2, 3)
multiply(1, 2)(3)
multiply(1)(2)(3)
Enter fullscreen modeExit fullscreen mode

I realise as I'm typing this my explanation is quite convoluted but hopefully it makes sense!

Comment button Reply

CollapseExpand

CollapseExpand

This is an enjoyable series, keep it up :).

Vomit.

At first glance, it feels unusual for the multiply function to accept 3 arguments. I would expect either 2 arguments or a variable number of arguments (...args). However, that's up for discussion depending on the specific case.

Then, if it needs currying, it could be done with a curry utility instead. We can make our own or import the one from Ramda or something.

import {curry} from 'ramda';
const multiply = curry((a, b) => a * b);
Enter fullscreen modeExit fullscreen mode

EDIT: Finished comment after submitting early by accident...

Comment button Reply

CollapseExpand

Now I'm definitely going tot try currying, turns out I didn't know much about it 🙂
Really love this community thnx all! 😎

Comment button Reply

CollapseExpand

I don't really like currying, but that might be because I've never used it beyond watching people's explanations. I can't think of a use case which couldn't be done in a simpler, more readable way.

Comment button Reply

CollapseExpand

Currying on its own is simply a way to do partial application. Nothing more, nothing less. (Unless you subscribe to the fact that your code is easier to prove mathematically if your functions only accept one argument. But I've never had my code mathematically proven in my professional work.)

For example:

import {multiply} from 'somewhere';

// with currying
const double1 = multiply(2);

// partial application without currying
const double2 = (number) => multiply(number, 2);

// inline is shortest because you don't have to import
const double3 = (number) => number * 2;
Enter fullscreen modeExit fullscreen mode

As you can see, the curried implementation is slightly cleaner and shorter if you need to do partial application (fix arguments on an already defined function). For complicated functions, you need to do partial application. You can't just redefine them inline every time you need them.

But as you can see, the benefit is small.

But, in programs written in a functional programming style, we do this a lot, so the little cleanliness of currying adds up.

For example:

// with currying
const operation = compose(baz(7), bar(5), foo(2));

// with normal partial application
const operation = compose((number) => baz(7, number), (number) => bar(5, number), (number) => foo(2, number));

// with imperative code
function operation(number) {
  const result1 = foo(2, number);
  const result2 = bar(5, result1);
  const result3 = baz(7, result2);
  return result3;
}
Enter fullscreen modeExit fullscreen mode

So yeah, small benefit overall, but can make some things cleaner if you're used to the syntax.

Hope this is somewhat useful, even if it wasn't asked for :).

Comment button Reply

CollapseExpand

Wow thanks! Great example and clear explanation, really useful ☺️

Comment button Reply

CollapseExpand

I felt exactly the same.. but this post changed my mind, some great explanations here ☺️☺️

Comment button Reply

CollapseExpand

I guess this is great for plugin-based libraries like UnifiedJS? So you can do like:

unified()
       .use(pluginA)(pluginB)(pluginC)
       .process('# Hello there!', (err, file) => console.log(String(file)))
Enter fullscreen modeExit fullscreen mode

Comment button Reply

CollapseExpand

Definitely 🤢!

This way it is much easier to read:

const mul = a => b => c => a*b*c
Enter fullscreen modeExit fullscreen mode

Comment button Reply

CollapseExpand

Is the question "do we like currying as a feature?" or is it "do we like this style of currying?" @jmdejager

Comment button Reply

CollapseExpand

I understood the question as "do you like this code", regardless of currying as a concept.

Thread

Thread

yes that's the idea of ✔|| 🤢 but the example obviously wasn't clear enough. I'll make some changes for future viewers 😎

Comment button Reply

CollapseExpand

good question, it was meant as currying as a feature but... it is commit or vomit so I gues would you commit the code or not.

Thread

Thread

In that case, what the code does would maybe better be described as "manual currying", as normally the word refers to something that happens automatically (often even on a language-level).

Doing this manually can be useful in edge-cases, but just currying every function for good measure is definitely a bad idea.

  • ✔ When done for a reason
  • 🤢 When overused

Comment button Reply

CollapseExpand

It certainly takes as bit of a shift in thinking to use currying successfully. I'm not sure I ever manually wrote a curried function tho except when learning how it works. I use Ramda.curry(fn)

Comment button Reply

CollapseExpand

After reading and typing "currying" so many times I really want to make curry now. (For those who don't know: the word currying isn't related to the food)

Comment button Reply

CollapseExpand

CollapseExpand

I love using currying in React in function helpers actually!

Comment button Reply

CollapseExpand

I never used it so decided to give it a try 😊
Curious as to how it can help me. Watching it I think it looks somewhat confusing and takes time for people who don't know it. But hey, always open to new stuff 🧐

Comment button Reply

CollapseExpand

Yikes! 😱 Not the best thing to look at shortly after waking up! My mind's in a knot 😵🥴

Comment button Reply

CollapseExpand

Let me google that before I can actually decide what to do with it😅😂😂

Comment button Reply


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK