DEV Community

loading...
Cover image for βœ”||🀒 Commit or Vomit | function currying πŸ›

βœ”||🀒 Commit or Vomit | function currying πŸ›

jmdejager profile image 🐀πŸ₯‡ Jasper de Jager ・1 min read

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 mode Exit 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

Discussion (25)

Collapse
jackmellis profile image
Jack • Edited

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 mode Exit fullscreen mode

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

Collapse
jmdejager profile image
🐀πŸ₯‡ Jasper de Jager Author

It does make sense! Thank you ☺️

Collapse
avaq profile image
Aldwin Vlasblom

As a user of Sanctuary (the more opionated and strict alternative to Ramda), I use almost exclusively curried functions. To make this style of programming more readable, I use the coding style described here: github.com/sanctuary-js/sanctuary/...

It may seem jarring at first, but after working with it for some time you might find yourself like me, unwilling to go back; Turns out having each argument between parens makes multi-cursor editing a bliss: editors always have great support for parens-based selection and jumping and stuff. But more importantly, the utility gained from being able to use composition and other function combinators is huge.

Collapse
avaq profile image
Aldwin Vlasblom • Edited

Applying the style mentioned above, your snippet would look like:

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

It's a minor change, but for many that breathing room makes all the difference, especially in larger bodies of code.

Collapse
jmdejager profile image
Collapse
sargalias profile image
Spyros Argalias • Edited

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 mode Exit fullscreen mode

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

Collapse
jmdejager profile image
🐀πŸ₯‡ Jasper de Jager Author

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

Collapse
darkwiiplayer profile image
DarkWiiPlayer

Definitely 🀒!

This way it is much easier to read:

const mul = a => b => c => a*b*c
Enter fullscreen mode Exit fullscreen mode
Collapse
jackmellis profile image
Jack • Edited

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

Collapse
darkwiiplayer profile image
DarkWiiPlayer

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

Thread Thread
jmdejager profile image
🐀πŸ₯‡ Jasper de Jager Author

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

Collapse
jmdejager profile image
🐀πŸ₯‡ Jasper de Jager Author

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
darkwiiplayer profile image
DarkWiiPlayer

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
Collapse
moopet profile image
Ben Sinclair

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.

Collapse
sargalias profile image
Spyros Argalias • Edited

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 mode Exit 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 mode Exit 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 :).

Collapse
jmdejager profile image
🐀πŸ₯‡ Jasper de Jager Author

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

Collapse
jmdejager profile image
🐀πŸ₯‡ Jasper de Jager Author

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

Collapse
nefomemes profile image
Nefomemes • Edited

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 mode Exit fullscreen mode
Collapse
darkwiiplayer profile image
DarkWiiPlayer

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)

Collapse
jmdejager profile image
🐀πŸ₯‡ Jasper de Jager Author

I'd also really love some curry 😍

Collapse
johnkazer profile image
John Kazer

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)

Collapse
technoglot profile image
Amelia Vieira Rosado

Yikes! 😱 Not the best thing to look at shortly after waking up! My mind's in a knot 😡πŸ₯΄

Collapse
theowlsden profile image
Shaquil Maria

Let me google that before I can actually decide what to do with itπŸ˜…πŸ˜‚πŸ˜‚

Collapse
kaspermroz profile image
Kasper MrΓ³z

I love using currying in React in function helpers actually!

Collapse
jmdejager profile image
🐀πŸ₯‡ Jasper de Jager Author • Edited

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 🧐

Forem Open with the Forem app