Hey everyone, nice to see you on my little home on internet! I'm going through some concepts which I had skipped while beginning to learn JavaScrip...
For further actions, you may consider blocking this person and/or reporting abuse
Good summary on the fundamentals of currying, Tulsi.
I use curried funcs (funcs that return funcs) every day.
However I do not use them for reuse sakes. i.e. to define new functions (that's too much like inheritance).
I will define a func that has two or more parameters — and who's purpose is to be used in a pipe — as a curried func (nested func).
This allows one to delay final execution until the final value for the pipe is satisfied.
So a curried func is simply a closure.
So I think in terms of making pipeable funcs, which are a more generalized design pattern than currying since it applies also to uncurried funcs that take zero or one argument.
Btw, here is an example screenshot of method chaining verses functional pipelining.
Note that the funcs in the functional pipeline may or may not be curried, but they are all pipeable funcs.
Yeah, thanks for sharing a real world insight into using currying.
I've used method chaining for uncountable times however I am new to the term piping, but do understand the concept of it though. If possible, can you show a small example of how to make piping functions and how they're useful?
Hey Tulsi,
It turned out to be a big example :), so I posted it here...
dev.to/functional_js/a-functional-...
Great explanation on a not so easy concept.
However you should always put the "point" (argument on which the partial application operates in the end) in the last position :
This way you don't need to redefine functions, just :
Or write in a straightforward way :
Thanks for the great tip! I'll add this to the blog soon! 🤗
Finally got some time to update the post with this. Thanks again, for sharing!
Cool post! The motivation behind currying came from lambda calculus. In lambda calculus, you can only have anonymous unary functions. That means your function can only take one parameter and there's no way of calling other functions because they're anonymous, so the only way to do it is by nesting your function calls, a.k.a currying.
Here's the identity function. It takes 1 argument and returns it.
In pseudo javascript this looks like
What if we want the Kestrel/K combinator? In javascript, it can be expressed like this
But how would we do that in lambda calculus? By calling another lambda expression.
In javascript, this will look like
So, in javascript it looks like you can just have more arguments in your function. Why would you want to do currying if it's capable of taking in more than one argument? Well.. the cool thing about curried functions combined with naming them, is you can partially apply them.
And because you're using unary functions it's easier to identify the cardinality of each function.
EDIT: Using the above example with a compose function... coz partially applied functions with composition is pretty cool
Thanks for sharing the backstory behind currying! Now, I'll definitely keep an eye out when Lambda calculus comes up in my college. I'll have something to relate to! 💙
I'll echo that as I was struggling to understand why you would bother. Of course, lambda (something I don't yet use a lot) makes perfect sense.
Woah, this looks so clean.
From the code execution and efficiency point of view it's a nightmare. Instead of using full potential of your CPU you're making it sub-optimal the least by abusing function calls.
In normal situation you'd store the parameters in available registers or push them to the heap, store the stack pointer, redirect the code by updating the instruction pointer, use generic
add
instruction multiple times and then callreturn
and remove the address from stack.With curry function you're doing this multiple times increasing nesting, filling the stack (I don't want to debug this by looking at the stack trace, must look like a mess), making the code more vulnerable to thread unsafety as there is much more room when the thread can be pre-empted.
I can't see a reason why would anyone use this in production code. I assume any good compiler would inline those function calls anyways leaving you with significantly different debug and production code which might result in weird bugs that you cannot reproduce.
Normal function in IL:
Curry function in IL:
Benchmark:
the program:
Fantastic that you emphasize this. While FP code constructs unclutter the code, without proper tool support you just move the clutter into the runtime.
Indeed, JavaScript (nor C#) was never designed to go full throttle on functional programming concepts. Therefor the JIT compiler doesn't optimize any of it.
Languages like Haskell, F#, Erlang, Lisp, are built for this, and will handle it in a better way.
Thanks man, for putting this out here!
I'm definitely interested to know what happens behind all the functions and about compilation. However, I'm not quite experienced at it, but hopefully this will be helpful to others and even me in future.
Am I misunderstanding, or are the 2nd
console.log()
calls in your curryMultiply examples incorrect? Shouldn't they be callingcurryMultiply()
instead ofmultiply()
?You're very right, it was a mistake from my side of not cross checking the code on an editor. Don't know how I missed that.
Thanks a lot, I've updated it now. 😀
Great. However, were you supposed to update the first
console.log()
? Unless I misunderstand, the first one should just callmultiply()
.I did it to show that we can also use
curryMultiply
in the way we normally should have usedmultiply
function. Also, I felt it was kinda obvious thatmultiply(2, 4)
will always return8
as its just a normal function.You can call
curryMultiply()
with two parameters and it will pass them all? I thought it only worked with one parameter (I have a lot more experience with PHP and Go than with Javascript, so I do not know how JS works well enough.)If it can be used that way then can you please explain that in comments in the code snippet or elsewhere in the article to clarify for others who assume the same as me because that was not at all clear to me when reading?
Oops I got caught up in college stuff, apologies!
For now you can fiddle around with this repl to understand how it works! If possible, I'll add a line about this on the blog tomorrow. 🤞 Link to repl
The actual thing is as these two lines of code exist in our custom curry function:
We check if we already have got enough arguments that are necessary for the function to execute (or arity of that function), as in this case
curryMultiply(2, 4)
. If this condition holds true, weapply
(or invoke) the function right away instead of awaiting for another argument like we do for cases likecurryMultiply(2)(4)
which is when the else block of the code executes
Thanks for the detailed reply and REPL.
P.S. RE: "College stuff"; I don't envy you! I did my time years ago and thinking about it still gives me PTSD! :-D
Nice, didn't know that that technique was called currying. 😄
Yeah me too, I remember using them with Thunk and Connect functions with Redux, but never thought there'd be a name for this. 😜
Is either this or this that's the curry
I only had this curry in mind though! 😜