Currying in JavaScript
javascript.info
javascript.info
I'm not a big fan of OOP either, the older I get the more I end up writing a cross between procedural and functional code with the least possible abstractions in the way - while also trying to find the smallest natural coupling between blocks of code.
Patterns are very subjective, and they usually have a place where it's objectively good to use them - but I'm not sure about currying, it feels more like a hack for when you can't do what should be done to the underlying code.
I believe this is a notational issue more than anything. Fixpoint style in languages like Haskell is very natural and intuitive, if you have to write a `curry` function like the article shows, you have already lost.
It's much more convenient to `ad-hoc curry` with things like:
const f = x => myFunc(someArg, x, someOtherArg);
return myArr.map(f).whateverElse();In uncurried langages, generic curring has few use cases. Partial application does, and some libraries may want to provide both curried and uncurried versions of some things, but generally “curry” itself is unhelpful.
Partial application is the application of an n-ary function to k arguments (k <= n, often but not necessarily l < n) without actually evaluating (calling) the function, so given the same `f = (a, b, c) => d`, `partial(f, 1, 2)` returns a function `c => d`.
A closure is a function which "closes over" its lexical initialisation context and carries it along.
A curried function is trivially partially applicable, just call it with less than `n` parameters and it'll yield a (also curried) function taking `n - k` parameters. It's useful to build a language on that principle, it's not really useful to provide that as a generic utility, because in most scenarios you'd rather just partially apply a function.
A closure is a completely freeform tool so it can do more or less anything you want.
Theoretically they're equivalent, but practically not really especially when you introduce more complicated "imperative" features e.g. default parameters or overloading.
They also have API impacts e.g. because Haskell is curried, its HoFs are generally of the form `fn param`, that way you can trivially partially apply the callback and use the same partially applied function to different parameters.
In method-based languages, there is no way to partially apply the callback, and in uncurried languages in general since partial application is a secondary concern you'll often see the callback last regardless so the non-callback parameters don't "get lost" at the tail end of a long callback.
For example this allows you to write methods that only take 1 input and 1 output type arg and handle all function cases with any amount of arguments. e.g. in Java/C# you typically have lots of types/anonymous class shapes to define different function shapes to represent lambdas/functions.
e.g. C# delegate syntax (Java has a more verbose way to do this last time I checked)
delegate T Action<T>(); delegate T Func<T>(); delegate R Func<T, R>(T firstArg); delegate R Func<T1, T2, R>(T1 firstArg, T2 secondArg);
Java has things like Consumer<>, Supplier<>, Function<> etc. If you want more than a https://docs.oracle.com/javase/8/docs/api/java/util/function... you typically have to define your own template that's not standard.
However in curried languages all use cases typically are handled by one form and the compiler does the mapping for you (e.g Haskell, F#, etc).
type Func<T, R> = T -> R
The compiler translates a method like foo(a, b) to foo(a)(b) and has certain compile tricks to avoid intermediate allocations if you're specifying all the args at once.
In practice it means writing a LOT less overloads to deal with all the different argument length cases defined and a lot less "Function" types to consider. Instead of an overload in Java for example with Function, BiFunction, etc or C# with Func<>, Func<_, _>, etc you just write the one or two and chain it.
Currying and partial application are really nice when you have a pipeline operator, which is why the partial application and pipeline operator proposals are so intertwined.
users
|> List.map (fn user -> user.Email)
|> sendEmail
|> Result.mapError (fn _ -> "Error sending emails") errors = list()
for user in users:
if not sendEmail(user.email)
errors.append("Error sending emails")For what it's worth, your example doesn't map 1-to-1 to the intention of what I wrote. Doing it in a more imperative style, I'd have to write
emails = list()
for user in users:
emails.push(user.email)
res = sendEmail emails
if res.IsError:
Error("Error sending emails")
else:
res
(excuse my pseudo Python) try:
return sendEmail(user.email for user in users)
except IsError:
Error("Error sending emails") # if it does something
I agree FP pipelines are nice, but not everything needs it.Because I say "what" do to do without going into details of "how" I feel like I have spent less mental capacity reading this portion of code.
However, it does require your transformations to be simple and composable, shove a giant multi-line lambda in there it yes, the loop will be better.
Currying != partial application.
And while currying is useful in curried languages (to convert back from uncurried to curried), and partial application is useful period, the question is whether currying is useful, in general, in an uncurried language.
I don't think it is:
* You usually want to perform partial application, currying is an unnecessary intermediate step.
* Currying conflicts with rich "imperative" parameters e.g. overloading, default parameters, keyword parameters.
* Uncurried languages are usually imperative and effectful, that you have filled all the parameter spots does not mean you want to invoke the function.
Having a curried language is neat, and in curried languages converting back from uncurried to curried functions is tremendously useful. But it's not so for uncurried languages (which is most of them).
> which is why the partial application and pipeline operator proposals are so intertwined.
Again, partial application != currying. And pipeline operators can perform partial application (implicitly or explicitely) on their own. For a flagrant example, just see Clojure:
(->> users
(map :email)
(sendEmail)
(mapError (constantly "Error sending emails"))In particular I don't know what's meant by "curried" and "uncurried" languages
Currying is the conversion of an n-ary function into a chain of 1-ary function e.g. `fn(a, b, c) -> d` becomes `fn(a) -> fn(b) -> fn(c) -> d`.
Partial application is what it says on the tin, it only applies k parameters to the function returning an (n-k) parameters function, without actually running the function.
Currying is one method allowing partial application, but not necessarily the only one, or usually the best fit as it tends to not interact well with features like overloading, default parameters, keyword parameters, …
> In particular I don't know what's meant by "curried" and "uncurried" languages
Languages like Haskell, OCaml, or Elm are "curried" by default: when you define an n-ary function it's really just sugar for a chain of 1-ary functions; and the application of multiple arguments is similarly the implicit application of single arguments multiple times e.g.
map : (a -> b) -> List a -> List b
map f l =
case l of
[] -> []
(h::t) -> (f h) :: (map f t)
can be called as map fn [1, 2, 3]
or (map fn) [1, 2, 3]
the semantics are identical, which is not the case in an uncurried language like Javascript or Python: map(fn, [1, 2, 3])
and map(fn)([1, 2, 3])
will behave very differently unless the implementer has taken special steps to handle this case e.g. dynamic behaviour based on an optional second parameter, overloading, etc…What would be the use of this? Just delaying the execution of the function's side-effects?
I'll tip my hand: I'm working on a JS-like (and JS-targeted) language that I want to support partial-application/currying by default. Under the hood everything is represented in a curried way, but syntactically you can both define and invoke/partially-invoke functions with the more familiar syntax (commas). But this is fully superficial right now; it all happens at the parser level. Is there a downside to doing things this way?
For defaults/optionals, given "fn f(x, y, z=10)", if "f(1, 2)" evaluates to "f(1)(2)", does that return a function or the result of "f(1)(2)(10)"? What if you have "fn f(x, y = 10, z)"? All of this is a lot easier if you can evaluate the full argument list at the time of function invocation.
As for keyword arguments, they just don't play well with any kind of enforced ordering.
I wonder if that ambiguity could be resolved using contextual type info? I.e. if one of the two interpretations fits the expected type, use that. Otherwise, type-error.
Maybe that would be confusing, not sure.
I read your post yesterday. Good luck with your language!
To be honest this comments section has me seriously reconsidering the "everything is partially-applicable by default" feature, haha.
add :: Int -> Int -> Int
This is a function that takes one integer and returns a function which itself takes another integer and then finally returns an integer. Syntax sugar allows you to define it and call it like a single function.An uncurried function in these languages is a function that takes multiple arguments as a tuple.
add :: (Int, Int) -> Int
You don't see a lot of functions defined this way in Haskell because there isn't really any advantage to doing so in a lazy, pure language. It's more common in Standard ML from what I've seen, because SML is strict and impure.This doesn't contradict anything you said, but I think Idris is a language that curries everything and has default parameters.
https://docs.idris-lang.org/en/latest/tutorial/miscellany.ht...
users.stream()
.map(User::getEmail)
.map(Email::send)
.map(res -> "Error sending email: " + res)
.collect(toList())with elixir (the previous example) you'd likely use simple hashmaps or lists like {email: "mail"} or [:error, "reason for failure"].
That doesn't sound like its amazing, but actually is in practice, because the whole language is written with that in mind (pattern matching to effectively do function/method overloading depending on the value of each argument for example)
its very concise while still being very explicit. The same would be possible with java, but you'll need to create a lot of classes/interfaces/enums/boilerplate to facilitate it.
i'd still prefer java any time at a dayjob though, because boring and dumb is generally better if you need to write code that's gonna be in use for decades... and likely going to be changed by a lot of people with varying levels of experience.
No, in most cases you don't. The stream interface is mostly designed around simple Lists, Sets and Maps. It also interacts very well with the Collection framework (e.g. myHashmap.entrySet() yielding a set, etc.) which is part of the standard library.
You can extend streams with custom collectors, but rarely if ever you need to define intermediate data structures. You do need to define initial and terminal structures, but I'd argue that's good practice regardless.
that lets you pass the result from each function to the next without explicitly stating what form they have, yes.
You'll still be missing the conciseness/explicitness because the language isn't meant to be used like that and is missing necessary features in order to facilitate it such as pattern matching by the passed in values into function.
to make a simple example, you could theoretically write the following pseudo-code
def sendEmail({email}) do
// send email
end
def sendEmail({id}) do
// get email address
sendEmail({email})
end
sendEmail({id: 244})
or to make sure your code stops executing if an error occurs (positional return values this time) [:ok, msg] = sendEmail(lkajsdf) .collect(Collectors.groupingBy(...))maybe actually learn to program sometimes, then you will figure out what it does.
https://docs.oracle.com/javase/8/docs/api/java/util/stream/p...
An error could be a malformed e-mail address, or a timeout from the e-mail server.
What you do not want is to send 10000 e-mail, then have an error like "Error sending emails", then re-run a few time, only to have some people receive 5 e-mail, and some people receive 0 e-mail.
Consider advanced component creation in virtual dom frameworks. Components may want to yield some render responsibilities to the end-user while not exposing their inner api. They can use currying here to hide details from the end-user while providing their own public api.
I've also seen it be useful when you have sub components editing different parts of a model. You write one generic prop-assigner setModelProp(prop, val) alongside the model in the scope that owns the model. Then you give each subcomponent a curried setter with the prop locked in. Those sub-components don't have the ability to edit the model any other way now, and you haven't written a ton of boilerplate setters.
That's really not true. The Y combinator is not generally useful for instance, because every modern language supports recursion.
> Currying is indispensable in some composability workflows.
It's not.
> Then you give each subcomponent a curried setter with the prop locked in.
That's partial application, not currying.
There are convenience use cases for libraries providing curried versions of some functions e.g. you might want to provide both `setModelProp(prop, val)` and `setModelProp(prop)(val)`. But that's because you expect significant use cases fo partially applied versions of the utility functions. Currying is not necessary for this, it just makes things more convenient for users.
In that case I don't know any indispensible situations for currying.
I wish I had been told that before trying to understand and actually use it. I once wrote a JS benchmark based on Rosetta code to compute Fibonacci numbers. Not only is the Y combinator code convoluted and quite hard to understand, it's also between 1e5...2e5 times slower than a plain iterative implementation.
Somehow I find it ironic to post such a result here.
Dependency injection and currying both do the same thing, and they are both useless most of the time just like Inheritence. You want to avoid nesting as much as possible. We should be rejecting dependencies. We should be returning values and passing them through functional pipelines.
All together, "Favor composition over inheritence" is like "Favor pipelining over currying/dependency injection".
There's an example of a pipeline down the thread in p2t2p's comment[1].
The point being, essentially they are the same thing, they hold the same power, and it's just a stylistic difference.
Mark Seeman's blog[0][1][2](many more related articles, these are particularly related) helped me grasp some of this stuff.
[0]: https://blog.ploeh.dk/2014/06/10/pure-di/
[1]: https://blog.ploeh.dk/2017/01/30/partial-application-is-depe...
[2]: https://blog.ploeh.dk/2017/01/27/dependency-injection-is-pas...
Free yourself from the dogma, just do what makes sense.
I dare mention Rich Hickey and his talk “Simple Made Easy”, and postulate that we should be using whatever abstraction is _the simplest_ (not the easiest one) to reason about, to which the grand parent rightfully refers, as far as I understand.
Objects are easy to many, but far from being objectively simple.
I can't find it but there once was a blog that expressed this as: Reddit is a site where you can talk about anything with the exception of a few banned topics. Voat(might have been another reddit clone?) is a much less popular site where you can talk about anything. What do they talk about on Voat? Only the few topics banned on reddit.
While is strictly more powerful than for, for is strictly more powerful than foreach, foreach is strictly more powerful than map. And yet 95% of the time, the power in map is sufficient. Therefore 95% of the time you should use map. When you encounter a foreach, you should be expecting non-purity. When you encounter a while, you know that it's doing some recursive operation that requires that power.
This let's you reason about it. This allows you to compose these less powerful things.
[0]: https://blog.codinghorror.com/the-principle-of-least-power/
I have no preference for either fyi.
half = (`div` 2)
Also, I think the idea with curried languages is that you're supposed to write your functions with the parameter that people are most likely to want to curry first.What about partial application of named parameters?
Builder pattern. In a language that accommodates it well, such as Elm, it would look like this:
IconLib.downloadIcon
|> IconLib.withSize 12
|> IconLib.withColor "red"
|> IconLib.withCssClass "dl-icon"
Allowing currying of any parameter like: standardDownloadIcon = IconLib.downloadIcon
|> IconLib.withSize 12
largeDownloadIcon = IconLib.downloadIcon
|> IconLib.withSize 16Same here. I think this is a correct approach, sprinkled with some reactive code here and there (prefer reactive over other abstractions such as 2-way binding et al).
```
The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures."
Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
```
Currying (and closures) are great when you don't want to go through the overhead of constructing an entire object just to hold state. They're lightweight pseudo-objects. But the moment the number of variables you are closing over starts getting too big, it is better to formalize it into an object instead. That's how I interpret this story.
Why do closures and objects arise in such a natural fashion? I'm not entirely sure, and I don't think there's one right answer. All I can think is that I can't imagine the depth of Alan Kay's knowledge on the subject, given he pioneered scheme and smalltalk, two languages that define the core of the closure/object paradigm.
My reasoning is we need a partitioned stateful function which is impossible to achieve and the alternative are worse:
- partition global state with your own object id
- passing all state as arguments
- Managing state through a monad or effect system
- Managing state through coroutines / continuations
- Managing state through dynamic scoping (poor man's effect system)
- Associating implicitly mutating functions with types without having full objects (Rust)
Some of these are pretty powerful, especially effects and continuations. I think the reason we don't see more of them is because we haven't figured out a wholly ergonomic way to fit them into a language yet.
This implementation I wrote is much more elegant and performant than the O(n) stack frame crud in that article:
const curry = fn => {
const curried = (...a) => a.length >= fn.length ? fn(...a) : curried.bind(undefined, ...a)
return curried
}
In fact, I can't think of any implementation in JS that would be more performant, using any paradigm, functional, object oriented, or imperative.Try to best it if you can. I'm curious to see what HN can come up with ;-)
The only difference is that currying would ignore any additional parameters in a flexible language like JS.
It's easy to make this implementation only consider the first parameter. See below.
const curry = fn => {
const curried = (a,x) => a.length + 1 >= fn.length ? fn(...a, x) : curried.bind(undefined, [...a, x])
return curried.bind(undefined, [])
}
I still don't understand your point about eager execution. The function is supposed to be executed when enough parameters have been passed. I suppose you mean that JS does not check if the call arguments length equals the function signature, so strict currying is safer to avoid errors? If so, that makes sense. I tend to consider that caveat of JS a feature though, which is why partial application is what I'd use to accomplish currying. It subsumes it and provides more flexibility by allowing multiple arguments to be curried in a single call.Which makes perfect sense for languages which are mostly side-effect free and in which functions with no parameters do not make sense.
That's not the case of Javascript, partially applying all the parameters but not wanting to actually run the function is a useful thing to desire, and not doing that makes partial application incoherent, especially as e.g. default parameters get involved.
That is why currying is a bad fit for imperative languages, but partial application is a useful tool still.
sum = curry((a,b,c) => a+b+c)
sum(1)(2)(3) equals 6 under currying.
sum(1,2)(3) equals 6 under partial application.
Perhaps you are thinking of calling the function with no arguments as a signal to execute the final calculation. That is NOT how currying normally works.
I believe you think currying works like this:
sum(1)(2)(3)() = 6
This is NOT standard currying. There is never a need to give an empty call to signal execution in standard currying as CS and Mathematics define it.
The implementation I provided is defacto currying by the book. Perhaps you can provide an example if we are misunderstanding eachother.
Currying does not, partial application can (and should).
> sum = curry((a,b,c) => a+b+c)
> sum(1)(2)(3) equals 6 under currying.
> sum(1,2)(3) equals 6 under partial application.
Sure. Now what happens to `sum(1, 2, 3)`? Or if the function is `(a, b, c=1) => a + b + c`?
> Perhaps you are thinking of calling the function with no arguments as a signal to execute the final calculation. That is NOT how currying normally works.
Which is the point. It's not how currying works. It is, however, how a "regular" version of partial application works e.g. Javascript's Function#bind or Python's `functools.partial`.
> I believe you are confused.
Nope.
> I believe you think currying works like this:
No.
> The implementation I provided is defacto currying by the book.
"Currying by the book" does is defined for strict arities and can not generate variable-arity functions.
I've created a curry which will only execute when called with no arguments, ie. sum(1)(2)(3)() = 6
This is like you mentioned, a much better suited technique of currying for a language like JS:
const curry = fn => {
const curried = (a,...x) => x.length === 0 ? fn(...a) : curried.bind(undefined, [...a, x[0]])
return curried.bind(undefined, [])
}
// equals 15 because default c=10
curry((a,b,c=10)=>a+b+c)(2)(3)()
We can also apply the same idea of an empty call as a signal to the multi-argument currying variation.
I'd love to know what you think. And please keep reading. Because I apologize and stand corrected. Apparently partial application is single use, unlike currying. Essentially a fixed point. I have learned something today. I apologize for being so hard headed. Thank you for putting up with me and correcting me. The wikipedia article on currying confused me with regard to partial application but then I read the partial application wiki article and what you are saying clicked.It seems like there are 3 techniques here.
Multi argument currying. Single argument currying. And partial application (aka binding)
And too many references called the former the latter, hence my confusion.
Partial application is very useful (and you're correct that it's "one shot", though you can obviously layer partial applications by partially applying the result), so can the odd curried version of a library function (ideally provided by the library) be, but general-purpose currying… not so much I would say: the languages don't care for it (unlike curried language), it interacts badly with complicated parameterisation (varargs, default, keyword, …), and the almost entirely of the use cases is covered by straight partial application. What little is left can simply be curried by hand.
----------
This brought to mind my introduction to OOP by a talented but notoriously inarticulate programmer:
NIP: Do you know what OOP is?
Me: No.
NIP: Ah. Well, you have objects and methods. Objects: objects aren't anything. And methods are how you talk to objects. Okay?
Me: Sure.
I knew there was no point in asking questions -- this was the man at his most expository. I took him to mean, "Forget what objects are, just work with them."
-------------
Which I take to mean "Objects are black boxes. How they behave is what they are"
(define (make-queue)
(define data empty)
(lambda (cmd [arg #f])
(match cmd
['enqueue (set! data (append data (list arg)))]
['dequeue
(define value (first data)
(set! data (rest data))
value])))
Don't see the connection yet? Let me try again. (define (make-queue)
(define data empty)
(define (instance cmd [arg #f])
(match cmd
['enqueue (set! data (append data (list arg)))]
['dequeue
(define value (first data)
(set! data (rest data))
value]))
instance)Lucky for us there is a partial application proposal, albeit still in stage 1, which makes partial application—to make functions curried—a lot easier[2].
Mh, it's already 4 years old. What a shame.
To make matters worse it appear that generally OOP style darlings such as static class blocks and true private fields seem to gain more momentum.
” To improve the compositionality of our code we had defined a ton of curried functions using Ramda. But every abstraction has a cost associated with it. On profiling, we found out that the `curry` function was taking up a lot of CPU. Benchmarks show that removing curry from the code makes it up to 100 times faster. Curry function is at the core of Ramda, almost every function is curried.”
https://blog.dream11engineering.com/lessons-learned-from-run...
I'm a pretty big fan of strong, static type systems and FP in general, and I have been writing typescript professionally for a few years now.
I decided a long time ago that trying to write Haskell in TS just isn't worth the effort.
Adopting FP ideas such as pure functions, restricting side-effects and then otherwise just using the type system to model the flow of your program goes a very long way. You don't have to write Haskell in TS to reap most of the benefits.
As far as I understand it TS is supposed to follow as closely to JS as possible. I always saw it as “let’s add types to JS” rather than a separate language. I’m not sure I’ve seen a “this is how you write TS vs JS” formal declaration from the TS team. Am I missing something?
In this sense, where these features are not the default and aren't first-class, will almost likely never be idiomatic because to TypeScript because there's too much friction compared to something from the ML families or the LISPs. In trying to add types to JavaScript, as a result you keep a lot of that same friction as JavaScript. I'm not saying it doesn't have a place--it's clearly super popular--but I do think it does not offer a good experience for someone looking for FP-style programming. It's really odd to see job postings with an FP team, Haskell on the back-end, and then TypeScript on the front-end... it just doesn't match, and there were other good options, even if it requires writing some libraries for these communities.
1: https://github.com/ramda/ramda/blob/master/source/curry.js 2: https://github.com/ramda/ramda/blob/master/source/internal/_... 3: https://github.com/ramda/ramda/blob/master/source/internal/_...
value |> fn(?, "static string")
However earlier this month they advanced a version of the pipeline operator with a definite topic marker which makes partial application useless in the RHS of the pipeline operator. This was of course really controversial, as you can see if you read thought the most resent issues (particularly the closed ones).Here are some trivial examples. As you increase the N, the closure containing ones get faster, except the last one (Chrome/M1). I think in real world scenarios the benefits of the optimizations are less clear cut and also the reason why V8 has a reputation for being a bit of a memory hog which is why we should give it a hand and write dumb imperative code.
https://perf.link/#eyJpZCI6InN0NmQ4cTRrd20zIiwidGl0bGUiOiJDb...
A lot of people here asking "why". Only solid example of it being the more elegant solution (in my opinion) is on the front end with redux.
Maybe you have a large amount of objects in state. Each object has many properties and is used by many components. If you are using an implementation pattern that predefines selectors, you don't want tons of different functions selecting one property each. The simpler way is a single selector that "picks" the property dynamically by currying the property name to the single, more general selector.
The real-world example doesn’t tell me why I would prefer currying instead of putting the date at the end and making it optional, then checking if missing to assign current date. And for the other argument I could create separate functions logDebug, logWarning and logError, those would call the generic function with fixed strings, right?
Sure, but what would you do if e.g. the importance string isn't fixed? Well, you might write a function that takes in the importance string and returns a function that calls the generic function with the dynamic string. That's currying.
`sendEmail(mockEmailService)(to, subject, body) `
I find it helps to differentiate between side-effecting dependencies and parameters, making code purer, easier to test, more scalable etc.
Trying to use currying in languages where it isn't built in makes no sense to me. It doesn't seem to compare well against doing the obvious partial application with a lambda. And it doesn't play well with variadic functions, default arguments, etc. (I have ideas for automatic currying of record types that I hope to explore in a toy language at some point, but that only does so much.)
From searching for practical applications a while back, I understood currying as a way to create a new function with fixed values rather than fixed arguments. Meaning if you had a function take arguments FIRST and SECOND, with FIRST being computationally expensive, currying would allow you to create a new function with the slower part pre-calculated.
But after brief testing I’m unsure that’s the case. It seems the examples might’ve been referring to the argument itself being a computationally expensive operation, in which case—and going back to your example—you could save the computation’s result to a variable beforehand and use that.
For example, if you want to pass an object to onClick event:
const handleOnClick = _.memoize(
(myObj) =>
(evt) => {
// you can do something with myObj here
});
// on render
return <button onClick={handleOnClick(myObj)} >Try it</button>;
Memoize works on class component but I don't know if it works on function component.Or a function that return new date, but it'll make things complicated.
It's the function caller that's responsible for that parameter with partial application / currying / closure.
It doesn't matter if you develop both, but if you use a library you'll need partial application to define default parameter.
Also you totally do not need to be able to call `f( a, b ,c )` as `f( a )( b )( c )`, rather, you should avoid the latter for reasons of clarity, simplicity, and performance. You'd be just producing anonymous single-use throwaway functions for no good reason at all. You do not want to curry when you can just `g = ( a, c ) => f( a, 'xy', c );`. This is simpler, clearer, more flexible, and more to the point. Where this is not enough, just use a class. Everyone talks about inheritance, but where classes shine is that you can bind a multitude of functionality (implemented in methods) to a single set of configuration data (`this`) (and mutable state where called for).
Currying can lead to code that looks simpler, but I believe it hides real complexity in a non-obvious way. Well-named wrapper functions like ‘logNow’ can be great, but arbitrary curried functions are too tricky to keep track of on teams that include juniors, backend engineers and experienced senior FE too.
What are some ways you've seen it abused in JS projects?
let logNow = log.bind(null, new Date()); // [sic, "now" is fixed]
let debugNow = logNow.bind(null, "DEBUG");
Also, uglifiers and transpilers do some horrifying stuff, this won't break if fn.length is tempered with. Unlike the article implementation. const one = curriedSum(1)
one(2)
is the same as const one = sum.bind(null, 1)
one(2)
with the exception that the latter is explicit and not as slow as `curriedSum`.Both `sum` and `curriedSum` can be used the same way:
curriedSum(1)(2)
sum.bind(null, 1)(2)
or just: curriedSum(1, 2)
sum(1, 2)
One of the advantages is that non-curried functions make the return value explicit. You can't implement `sum(...addends)` with currying because curried functions have a fixed number of parameters. Once past that, a call will not return a function anymore. sum.bind(null, 1).bind(null, 2).bind(null, 3).bind(null, 4) // Still not called
curriedSum(1)(2)(3)(4) // Maybe it works, maybe undefined is not a functionGotta say currying seems to be useless in real world. No advantage whatsoever over partial application.
If we are being pedants. Wikipedia says:
> currying is the technique of converting a function that takes multiple arguments into a sequence of functions that each takes a *single argument*.
So the article isn't currying either. It's a hybrid between currying and partial application.
TBH I can't think of a practical case where you'd prefer currying over partial application. Theory/philosophy aside.
Sure.
> TBH I can't think of a practical case where you'd prefer currying over partial application. Theory/philosophy aside.
For eager-evaluation uncurried language (like javascript) I would also struggle to think of one.
For curried languages, it can sometimes be useful to uncurry functions in order to make types match, after which you might have to curry them back into the "normal" form to use them.
let logNow = (importance, message) => log(new Date(), importance, message);
let debugNow = message => logNow("DEBUG", message);
And with this implementation, current IDEs provide a more informative auto-complete.Whenever I run into a curry, I can usually solve the same issue with a simple for loop that makes it instantly clear what the code does, always.
A question for the Javascript experts: is there a way to set a property in the returned function, saying in what line of code it was created? Perhaps something like the __LINE__ macro from C...
const curry = fn => {
return (...args) => {
const curried = (...a) => {
args = [...args]
return args.push(...a) >= fn.length ? fn(...args) : curried
}
return curried()
}
} const sum3 = curry(( a, b, c ) => a + b + c )
const sum3_10 = sum3( 10 ) // ...
const sum3_10_20 = sum3_10( 20 ) // ...
sum3_10_20( 30 ) // 60
sum3_10_20( 5 ) // 60
One of the points of currying is to be able to fork the partial application of the function at any point. const curry = fn => {
const curried = (...a) => a.length >= fn.length ? fn(...a) : curried.bind(undefined, ...a)
return curried
}As for the inelegant claim, beauty is in the eye of the beholder. If performance is not a concern (as it won't be in most currying use-cases) I think the original version is much easier to read without years of js experience. It can be hard for newer or cross-discipline devs to understand mixed usage of rest params and spread operator since they look the same. In a scenario like this I think maintainability is a key ingredient of elegance.
const curry = fn => {
const curried = (...a) => a.length >= fn.length ? fn(...a) : curried.bind(undefined, ...a)
return curried
}
It uses bind which is an extremely powerful operator (a function that maps functions to functions)