[HN Gopher] Currying in JavaScript
       ___________________________________________________________________
        
       Currying in JavaScript
        
       Author : corentin88
       Score  : 134 points
       Date   : 2021-09-19 10:02 UTC (12 hours ago)
        
 (HTM) web link (javascript.info)
 (TXT) w3m dump (javascript.info)
        
       | anoctopus wrote:
       | Automatic, implicit currying is the Haskell feature that most
       | surprised me with how much I like having it. It makes taking
       | apart and composing functions so much nicer, by making a very
       | common case for partial application syntactically and mentally
       | cheap.
       | 
       | 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.)
        
       | ufo wrote:
       | In my experience, currying is problematic in dynamically typed
       | languages. If you accidentally pass less arguments than you
       | should, then you'll only detect the error much later, when you
       | try to use the result and find that it is a partially-applied
       | function instead of whatever you were expecting.
       | 
       | 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...
        
       | graftak wrote:
       | Currying is nice but in practice it's rather esoteric in the
       | JavaScript ecosystem. I've only seen currying being used (if at
       | all) when transforming data with utility libraries like ramda[1].
       | What makes it worse it that partial application is rather
       | cumbersome to type.
       | 
       | 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].
       | 
       | [1] https://ramdajs.com/docs/#curry
       | 
       | [2] https://github.com/tc39/proposal-partial-application
        
         | renke1 wrote:
         | The partial application proposal looks reasonable and
         | intuitive. Definitely something I would use. Is there any prior
         | art (other languages etc.)?
         | 
         | Mh, it's already 4 years old. What a shame.
        
           | weego wrote:
           | Scala has partially applied functions that use a very similar
           | idiom
        
           | alexfoxgill wrote:
           | It is used heavily in Scala
           | https://alvinalexander.com/scala/how-to-use-partially-
           | applie...
        
             | masklinn wrote:
             | Clojure has the "thread-as" macro (`as->`), but I don't
             | think it's used much: usually thread-first (`->`) and
             | thread-last (`->>`) will more than do the job and have less
             | mental overhead due to their regularity.
        
           | graftak wrote:
           | There's a lot of bikeschedding on how to use it in
           | conjunction with the (also stage 1 proposal and forever
           | delayed) pipeline operator[1] unfortunately. Add in never
           | ending arguments on which symbol we should use (the
           | questionmark has a lot of responsibilities already) and here
           | we are.
           | 
           | 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.
           | 
           | [1] https://github.com/tc39/proposal-pipeline-operator/wiki
        
         | runarberg wrote:
         | I have strong doubts that partial application will ever advance
         | from stage 1. The reason is that partial application was
         | supposed to compliment the pipeline operator[1].
         | 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).
         | 
         | https://github.com/tc39/proposal-pipeline-operator
        
         | eurasiantiger wrote:
         | Note that currying, especially with Ramda, has a very large
         | negative performance impact.
         | 
         | " 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...
        
           | mLuby wrote:
           | It also pollutes the call stack, making stepping through
           | functions that much more laborious.
        
           | IceDane wrote:
           | Wow, that is pretty awful.
           | 
           | 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.
        
             | toastal wrote:
             | You can also just _not_ use TypeScript if you want
             | something more appropriate for functional programming
             | styles. I know it 's not always practical to switch
             | languages, but it's equally impractical to push
             | unergonomic, unidiomatic styles on language not built for
             | it. There are a lot of good options to compile an FP
             | language to JavaScript, and frankly those languages deserve
             | more mindshare than pressing so hard on fp-ts.
        
               | khalilravanna wrote:
               | What's unergonomic or unidiomatic about TS?
               | 
               | 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?
        
               | toastal wrote:
               | Say you want first-class currying and function
               | composition. You expect this coming from any functional
               | language and now you don't have that ability without
               | introducing another compiler or third-party library. Do
               | you want algebraic data types and pattern matching? You
               | can sort of fake it, but it's certainly uglier. Do you
               | want managed IO or immutability? Well, you can code it by
               | convention but it's hard to enforce it and many of the
               | libraries you consume won't be following those
               | conventions.
               | 
               | 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.
        
           | brundolf wrote:
           | Wow. Was that just from the extra function instances and
           | closures being created?
        
             | eurasiantiger wrote:
             | The story doesn't tell, but looking at the Ramda source
             | [1][2][3], it sure looks like it: each application of a
             | curried function creates a new curried function on the fly.
             | Didn't check deoptigate, but I'm willing to bet V8 doesn't
             | optimize that well.
             | 
             | 1:
             | https://github.com/ramda/ramda/blob/master/source/curry.js
             | 2: https://github.com/ramda/ramda/blob/master/source/intern
             | al/_... 3: https://github.com/ramda/ramda/blob/master/sourc
             | e/internal/_...
        
       | thomas_moon wrote:
       | In my experience, currying is usually helpful as a hack and is
       | tolerable as long as you don't get carried away. One "curry" is
       | fine. Two+ is really pushing it and is probably a signal that
       | something should be refactored.
       | 
       | 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.
        
       | tomxor wrote:
       | I've actually grown to dislike currying, it seems like a neat
       | idea when you start using it, but whenever I come across it in
       | real life code it just results in layers and layers of yuk -
       | making me want to scream "show me the fucking code", you can go
       | through 100s of lines before seeing a single operator...
       | 
       | 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.
        
         | layer8 wrote:
         | One aspect I don't like about currying (at least with the usual
         | syntax) is that it privileges the first parameter of each
         | function. As soon as you want to curry on the second parameter,
         | you lose the "natural" currying syntax and have to fall back to
         | e.g. `half x = \x -> div x 2` or something like `half = flip
         | div 2`. That aspect, to me, makes currying nonuniform and
         | awkward, as in many cases the first parameter doesn't have a
         | particular conceptual distinction to single it out for
         | currying. It's a bit similar to how I don't like Smalltalk's
         | asymmetric syntax for commutative operations (e.g. `x add: y`).
        
           | mLuby wrote:
           | Agreed. I've come to view partial application as the original
           | coder saying "I guarantee you'll never need to inspect or
           | modify this parameter from now on." Obviously, that's rarely
           | true in practice.
           | 
           | What about partial application of _named_ parameters?
        
           | josephcsible wrote:
           | You can curry the second parameter without it being too ugly
           | like this:                 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.
        
             | layer8 wrote:
             | Of course that's the mitigation strategy, but my point is
             | that the usual currying syntax inherently special-cases the
             | first parameter, and in x% of the situations that's not
             | what you want. From a language-design point of view it just
             | feels awkward.
        
               | josephcsible wrote:
               | I guess that's fair. What about Scala's _ syntax, though?
               | Does it solve the problem?
        
         | danlugo92 wrote:
         | > 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.
         | 
         | Same 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).
        
         | ItsMonkk wrote:
         | Yep. I'm reminded of the advice "Favor Composition over
         | Inheritence", which begs the question "When can we not use
         | Composition and need to fall back down to Inheritence?" and it
         | turns out the answer is that you can always use composition
         | with the exception if you are relying on someone else's library
         | that does it wrong and you can't change it.
         | 
         | 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.
        
           | drenvuk wrote:
           | lmao, is this satire? We should be using whatever abstraction
           | is easiest to reason about. Sometimes that's apeasing the
           | primate brain with objects and things, sometimes it's shoving
           | those things through a pipeline.
           | 
           | Free yourself from the dogma, just do what makes sense.
        
             | nlitened wrote:
             | > We should be using whatever abstraction is easiest to
             | reason about
             | 
             | 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.
        
               | drenvuk wrote:
               | Rather than that I should've written, "we should use
               | whatever abstraction makes the problem easiest to reason
               | about".
               | 
               | I have no preference for either fyi.
        
               | ItsMonkk wrote:
               | I would have linked the Principle of Least Power[0], but
               | same idea. Rich certainly fleshes the idea out with more
               | examples and I deeply respect his opinions.
               | 
               | 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/
        
           | monkeyfacebag wrote:
           | I'm not following. How is dependency injection like
           | inheritance and also useless?
        
             | sfblah wrote:
             | I think GP is saying that dependency injection is like
             | currying, not that it's like inheritance.
        
             | ItsMonkk wrote:
             | "Favor composition over inheritence" is like "Favor
             | pipelining over currying".
        
               | monkeyfacebag wrote:
               | I'm still not getting the relationship to dependency
               | injection. What is pipelining?
        
         | qsort wrote:
         | > I've actually grown to dislike currying
         | 
         | 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();
        
           | masklinn wrote:
           | Currying makes sense if haskell because it's a curried
           | langage, so you may need the odd uncurry, then curry it _back
           | to normal_.
           | 
           | 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.
        
             | kortex wrote:
             | What's the difference between currying and partial
             | application/closures?
        
               | masklinn wrote:
               | Currying is the conversion of a n-ary function to a chain
               | of n 1-ary functions. So if you have a function `(a, b,
               | c) => d` (a 3-function which returns a result) and you
               | curry it it becomes a => b => c => d (a 1-fn which
               | returns a 1-fn which return a 1-fn which returns a
               | result).
               | 
               | 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.
        
               | brundolf wrote:
               | The distinction sounds almost completely syntactic. I.e.
               | foo(a, b) vs foo(a)(b). Is the former not just sugar for
               | the latter?
        
               | masklinn wrote:
               | > Is the former not just sugar for the latter?
               | 
               | 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.
        
               | brundolf wrote:
               | Ah that makes sense about default parameters and
               | overloading. Hmm.
        
               | kortex wrote:
               | So partial takes an N-ary function and gives an M-ary
               | function, while currying always turns an N-ary function
               | into N unary functions, that is the main distinction?
        
         | swman wrote:
         | Ugh my team at work is obsessed with DDD for a service with two
         | endpoints. Absolutely overkill and the levels of OO abstraction
         | are terrible. If this were more complicated I'd understand,
         | maybe I'm wrong in general. But writing a small Nodejs service
         | in such a way is terrible IMO.
        
         | neurotrace wrote:
         | I've felt this same sort of pain but I don't blame currying.
         | It's when currying and partial application is used for deep
         | dependency injection with no easy route to finding the original
         | function. I dabbled in writing an extension for F# that would
         | trace back function calls to give you all of the possible
         | original sources for a value. I think that would solve that
         | particular problem.
         | 
         | 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")
        
           | okasaki wrote:
           | I don't see why that's better than the good old for loop.
           | errors = list()         for user in users:             if not
           | sendEmail(user.email)                 errors.append("Error
           | sending emails")
        
             | HugoDaniel wrote:
             | nice one, however shouldn't good old for loops be done in
             | ALGOL instead?
        
             | p2t2p wrote:
             | For me, the functional/pipeline/call chain style changes
             | perception from "how" to "what".
             | 
             | 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.
        
             | neurotrace wrote:
             | The example I gave was contrived. I frequently find myself
             | modeling much of my logic as a series of data
             | transformations. The more I can model logic like this, the
             | easier it is to test.
             | 
             | 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)
        
               | BiteCode_dev wrote:
               | Excuses accepted. Imperative Python would really look
               | like:                   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.
        
           | p2t2p wrote:
           | Oh, the lengths people go to avoid OOP. Java:
           | users.stream()             .map(User::getEmail)
           | .map(Email::send)             .map(res -> "Error sending
           | email: " + res)             .collect(toList())
        
             | creata wrote:
             | What's "object-oriented" about that code? I'm suspicious of
             | vague labels like "OOP" and "FP", but even some of the Java
             | docs call Java's streams "functional-style".
             | 
             | https://docs.oracle.com/javase/8/docs/api/java/util/stream/
             | p...
        
             | y4mi wrote:
             | the only issue with java in this context is that you'll
             | need to create a new class/transfer object between each
             | function call that does things.
             | 
             | 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.
        
               | nestorD wrote:
               | Side note to say that the previous example is actually
               | F#, a static typed language contrary to Elixir (to be
               | fair Elixir was heavily inspired by F# and they look
               | similar when only looking at snippets).
        
               | qsort wrote:
               | > the only issue with java in this context is that you'll
               | need to create a new class/transfer object between each
               | function call that does things
               | 
               | 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.
        
               | y4mi wrote:
               | > _No, in most cases you don 't_
               | 
               | 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)
        
               | qsort wrote:
               | .collect(Collectors.groupingBy(...))
        
               | y4mi wrote:
               | that does something entirely different.
               | 
               | maybe actually learn to program sometimes, then you will
               | figure out what it does.
        
           | z3t4 wrote:
           | You usually want to send the e-mail in order, with a sleep in
           | between to not overload the e-mail server, and stop at any
           | error, so that you can fix the error and then continue from
           | where the error was.
           | 
           | 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.
        
             | neurotrace wrote:
             | I didn't think I had to make this clear but a lot of people
             | seem to be getting stuck on the specifics of my example
             | code. That example is doing nothing but showing a 5,000
             | foot view of what pipelines can do. Please don't take my
             | dumb example that was written early in the morning as The
             | One True Way of processing data, sending emails, or
             | handling errors. It's a horrible example of that
        
               | z3t4 wrote:
               | Simplified examples always look neat. Any code/syntax
               | will look simple if it doesn't have async, state and
               | error handling.
        
               | neurotrace wrote:
               | I can't be bothered to type all of it out on my phone but
               | even adding in those pieces, it doesn't change it much.
               | This is F# so you can easily manage the async via an
               | async computation expression, the retry logic can be
               | encapsulated in the `sendEmails` function, and the error
               | handling is reduced to a `Result` which is very easy to
               | work with in a pipeline. Not everything should be done in
               | a pipeline but pipelines make a lot of things a lot nicer
        
           | masklinn wrote:
           | > Currying and partial application are really nice when you
           | have a pipeline operator
           | 
           | 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"))
        
             | creata wrote:
             | > Currying conflicts with rich "imperative" parameters e.g.
             | overloading, default parameters, keyword parameters.
             | 
             | 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...
        
             | BiteCode_dev wrote:
             | Agreed, and I really with partial() was a builtin in
             | Python, instead of having to fetch it from functools.
             | partial() is useful regularly, and much more
             | explicit/flexible than a lambda for this specific use case.
        
             | brundolf wrote:
             | I'm not sure I fully appreciate the distinction you're
             | trying to make here: "currying != partial application". Can
             | you clarify?
             | 
             | In particular I don't know what's meant by "curried" and
             | "uncurried" languages
        
               | masklinn wrote:
               | > I'm not sure I fully appreciate the distinction you're
               | trying to make here: "currying != partial application".
               | Can you clarify?
               | 
               | 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...
        
               | brundolf wrote:
               | > applies k parameters to the function returning an (n-k)
               | parameters function, without actually running the
               | function
               | 
               | 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?
        
               | RexM wrote:
               | Bagel?
               | 
               | I read your post yesterday. Good luck with your language!
        
               | brundolf wrote:
               | Yes, thanks! :)
               | 
               | To be honest this comments section has me seriously
               | reconsidering the "everything is partially-applicable by
               | default" feature, haha.
        
               | djur wrote:
               | The downside is that curried functions make default,
               | optional, and keyword parameters difficult to implement.
               | 
               | 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.
        
               | brundolf wrote:
               | Got it.
               | 
               | 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.
        
               | flyingchipmann wrote:
               | If you come from typical oop background like java.
               | Imagine there is a function has 5 parameters, and you
               | need to to provide the first 3 first. Then later on you
               | are using this partially applied function somewhere else.
               | You can even reuse it later with different 2 params.
               | Compare to class, it's just like how you initialize an
               | object with certain values, then do something else with
               | this object.
        
               | djur wrote:
               | In Standard ML and Haskell, all functions are curried by
               | default -- they take a single argument, and the syntax
               | for defining multiple-argument functions is just sugar
               | for defining single-argument functions that return
               | single-argument functions. That's reflected in this
               | Haskell type signature for a function adding two
               | integers:                  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.
        
               | smohare wrote:
               | At a deeper level currying is just a specific application
               | of the Hom-tensor adjunction to the category of Sets. In
               | particular the curried function is equivalent to the
               | original. Partial function mappings is a restriction, and
               | inherently not a injection. That is, generally the
               | partial function is not in an equivalent Hom space to the
               | original function.
        
           | nestorD wrote:
           | Yes! Like having both pattern matching and tagged union type
           | in a language, it is the synergy of the features that makes
           | them significantly powerful.
        
           | runarberg wrote:
           | We were hoping for similar operators in JavaScript (pipeline
           | `|>` and partial application `?`). However TC39 just decided
           | earlier this month that we users of the language are not
           | worthy of such powers. This was off course meet with a lot of
           | resentment from many JavaScript developers, including my
           | self.
           | 
           | https://github.com/tc39/proposal-pipeline-operator
        
             | Zababa wrote:
             | Considering what happened with the monadic promises, that
             | was to be expected. I hope we'll at least have the
             | immutable records and tuples so that the JS engine can
             | implement them efficiently. This way JS will become an even
             | better compilation target.
        
         | somehnacct3757 wrote:
         | I mostly agree but every tool has its purpose. Currying is
         | indispensable in some composability workflows.
         | 
         | 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.
        
           | masklinn wrote:
           | > every tool has its purpose.
           | 
           | 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.
        
             | somehnacct3757 wrote:
             | I see, I had these two concepts conflated. I guess the
             | difference is currying returns a function and partial
             | application invokes the function.
             | 
             | In that case I don't know any indispensible situations for
             | currying.
        
       | leodriesch wrote:
       | Nice explanation, however I don't really see the use case for
       | currying yet. If you want functions with fixed arguments, you
       | could also just create a new function that calls the other with a
       | fixed first argument and just takes the other arguments. Am I
       | missing something?
        
         | goto11 wrote:
         | What you describe _is_ currying.
        
           | jhgb wrote:
           | Isn't that more like partial application?
        
             | [deleted]
        
             | schpaencoder wrote:
             | At that moment, Anton became enlightened.
        
           | Normal_gaussian wrote:
           | With the main benefit of being able to also transform the
           | argument orser or output value at the same time.
        
         | graftak wrote:
         | The most common case I've seen is when you want to map using
         | 'point free' style functions, i.e. "x.map(transformItem)"[1].
         | Another (more) common scenario--but not yet relevant in
         | JavaScript--is piping/composing functions[2].
         | 
         | [1] https://en.wikipedia.org/wiki/Tacit_programming
         | 
         | [2] https://github.com/tc39/proposal-pipeline-operator/wiki
        
         | ttiurani wrote:
         | What you're missing is that the curry() function is generic:
         | you don't need to manually write that new function, but just
         | type a simple oneliner using curry() to generate the function
         | you're describing.
        
           | leodriesch wrote:
           | Defining one function that just calls another with a fixed
           | argument is also a one-liner with arrow functions. And I
           | would argue that this would be easier to understand and
           | anyone reading the code wouldn't have to understand what
           | currying is.
        
         | latexr wrote:
         | > If you want functions with fixed arguments, you could also
         | just create a new function that calls the other with a fixed
         | first argument and just takes the other arguments.
         | 
         | 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.
        
           | jhgb wrote:
           | Currying should not create a function with anything fixed
           | that hadn't been fixed before.
        
           | r1cka wrote:
           | I believe you may be mixing the concept of currying with
           | partial application.
        
         | fendy3002 wrote:
         | Also useful in react. It's better to use `data-props` for
         | performance, but if somehow `data-` props cannot contain the
         | information (function maybe), you can use currying with
         | previously memoize it first.
         | 
         | 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.
        
       | es7 wrote:
       | In my 10+ years as a JS dev, I've seen this pattern in numerous
       | code bases. Inevitably it leads to bugs and confusion.
       | 
       | 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.
        
         | brundolf wrote:
         | I've never seen it abused, maybe just because the team cultures
         | didn't lend themselves to that, but I have used it in one or
         | two places myself where it was very helpful. The main one that
         | comes to mind is pre-binding callback to be passed down to
         | react components, so that the exact same function instance can
         | be passed on each re-render of the parent component and the
         | child component doesn't get triggered to render
         | 
         | What are some ways you've seen it abused in JS projects?
        
       | mjbrusso wrote:
       | In the `logNow` example, the date argument will be eager
       | evaluated, not lazzy evaluated. Am I right? So what was supposed
       | to be a real use case doesn't seem useful to me.
        
         | fendy3002 wrote:
         | Nice catch. Rather than date the author should've pass the
         | DEBUG constant instead.
         | 
         | Or a function that return new date, but it'll make things
         | complicated.
        
           | mjbrusso wrote:
           | However , to pass a constant I could use default parameter
           | value.
        
       | mnemotronic wrote:
       | ... and I still don't understand _why_ I 'd want to use currying,
       | except as a mental exercise in "look at the weird things I can
       | do".
        
       | jonplackett wrote:
       | Seems like more trouble than it's worth
        
       | elboru wrote:
       | To me the problem with this kind of explanations is that they
       | miss the "why". I understand "what" is currying and "how" to
       | implement it. But I'm missing the "why".
       | 
       | 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?
        
         | ImprobableTruth wrote:
         | >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.
        
         | misterpurple45 wrote:
         | We use currying at work to inject dependencies. E.g.
         | 
         | `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.
        
       | SPBS wrote:
       | Any discussion on the utility of currying (i.e. closures) vs
       | constructing an object with methods always reminds me of this
       | parable:
       | 
       | ```
       | 
       | 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.
        
         | isaacimagine wrote:
         | Closures and objects are both ways to pair code and data -- I
         | don't think the lesson is entirely about switching to objects
         | when a closure becomes to large; personally, I find it to be an
         | invitation to discover how and why code and data are paired
         | together in the first place.
         | 
         | 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.
        
           | fendy3002 wrote:
           | > Why do closures and objects arise in such a natural fashion
           | 
           | 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
        
             | isaacimagine wrote:
             | Other ways to manage state as well:
             | 
             | - 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.
        
         | srcreigh wrote:
         | If you don't mind using mutation for private state in a
         | functional language, objects and closures are kinda the exact
         | same thing.                   (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)
        
         | discreteevent wrote:
         | Slightly off topic, but later on in that Qc Na thread:
         | 
         | ----------
         | 
         | 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"
        
         | zwarag wrote:
         | Who is this Qc Na master? Is that a story from a book or a
         | legend from a forum board?
        
           | detaro wrote:
           | There's a bit of a tradition of writing such koans for
           | software topics. This one is from here:
           | http://people.csail.mit.edu/gregs/ll1-discuss-archive-
           | html/m...
        
         | goldenkey wrote:
         | Indeed but we can get around closures by using first class
         | operators like bind.
         | 
         | 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 ;-)
        
           | masklinn wrote:
           | That's not currying, that's partial application (except bad
           | because it forces the evaluation of the function if all
           | parameters are filled, which is often undesirable as
           | javascript is an eagerly evaluated language with side-
           | effects).
        
             | goldenkey wrote:
             | The implementation in the article is technically partial
             | application. I was just reproducing it. But you are
             | correct. Currying is a subset of partial application. You
             | can do currying through partial application. The function
             | is eventually called when the correct number of parameters
             | has finally been supplied. Currying lets you call a
             | function, splitting it in multiple calls, providing one
             | argument per-call. Partial Application lets you call a
             | function, splitting it in multiple calls, providing
             | multiple arguments per-call.
             | 
             | 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.
        
               | masklinn wrote:
               | > I still don't understand your point about eager
               | execution. The function is supposed to be executed when
               | enough parameters have been passed.
               | 
               | 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.
        
               | goldenkey wrote:
               | You're not making any sense to me. Neither currying nor
               | partial application delay running of the function once
               | all parameters have been passed. There is no eager
               | execution happening in the implementation I provided. I
               | believe you misunderstand when the original function is
               | supposed to be executed.
               | 
               | 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.
        
               | masklinn wrote:
               | > Neither currying nor partial application delay running
               | of the function once all parameters have been passed.
               | 
               | 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.
        
               | goldenkey wrote:
               | Thank you for helping me understand the issue with
               | default parameter values in a variadic language like JS,
               | which probably makes a nonstandard currying with an
               | execution signal more applicable.
               | 
               | 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.
        
               | masklinn wrote:
               | It's really no worries. At the end of the day, the issue
               | is really that mathematical / functional / "traditional"
               | currying is not really suited to imperative languages,
               | which is most of them, and notions of "advanced" currying
               | are -- I think -- throwing good money after bad.
               | 
               | 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.
        
       | 734129837261 wrote:
       | Just because you can doesn't mean you should. Shit, for adding an
       | array of objects with numbers just use a simple map/reduce
       | instead of confusing future developers with your fancy curry.
       | 
       | 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.
        
       | kesor wrote:
       | Cringe at the new Date() example ... will logNow() actually
       | create a new Date() each time? no, it will use the one provided
       | in the curry initialization.
        
       | goldenkey wrote:
       | The implementation in the submission is awfully inelegant, dated,
       | and slow. I quickly wrote up a fast elegant ES2021 solution and
       | tested it thoroughly. Below is the code, feel free to use it:
       | const curry = fn => {         return (...args) => {
       | const curried = (...a) => {             args = [...args]
       | return args.push(...a) >= fn.length ? fn(...args) : curried
       | }           return curried()         }       }
        
         | thrttnkrnl wrote:
         | Your implementation is broken for any function that has more
         | than two arguments.                  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.
        
           | goldenkey wrote:
           | Very good catch, thank you. Here is my take on a better
           | version that fixes the issue:                 const curry =
           | fn => {         const curried = (...a) => a.length >=
           | fn.length ? fn(...a) : curried.bind(undefined, ...a)
           | return curried       }
        
         | somehnacct3757 wrote:
         | I get the dated claim, but how is yours faster? It's nearly the
         | same logic written with syntax sugar, no? The differences I see
         | are that by using rest params instead of a deferred
         | Array.prototype.concat, you've lifted the Array instance
         | creation into all branches, where the original saves itself the
         | trouble in the invariant case. And yours defines a variable
         | whereas the original didn't. Is there some under the hood
         | reason why this version would be more performant?
         | 
         | 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.
        
           | goldenkey wrote:
           | The article's implementation grows the stack unnecessarily
           | through recursively nested closures. A commenter pointed out
           | a flaw in my code. This new implementation is even faster and
           | more concise by doing away with the closures (other than the
           | single inner closure):                 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)
        
         | dotancohen wrote:
         | The topic is not the implementation, but rather the concept. To
         | make the topic accessible to as wide an audience as possible,
         | including old C stogies, the traditional anonymous function is
         | much easier to understand.
        
       | zodiakzz wrote:
       | That's already built in to the language:                 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.
        
         | masklinn wrote:
         | That is not currying, it's partial application.
        
           | q-rews wrote:
           | Currying makes it implicit, but it's the same thing.
           | 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 function
        
             | zodiakzz wrote:
             | They're technically correct. And if you gotta write on HN,
             | you better get the terminology correct (and that derails
             | threads into interesting tangents often) so my bad.
             | 
             | Gotta say currying seems to be useless in real world. No
             | advantage whatsoever over partial application.
        
           | zodiakzz wrote:
           | Ah, TIL.
           | 
           | 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.
        
             | masklinn wrote:
             | > So the article isn't currying either. It's a hybrid
             | between currying and partial application.
             | 
             | 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.
        
         | g_b wrote:
         | Easier to read version:                   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.
        
       | asimpletune wrote:
       | I remember feeling very excited the first time I ran into a
       | legitimate situation, where there was no better way to do things
       | than curry the function.
        
       | weatherlight wrote:
       | Currying is useful, especially if you are doing point-free style
       | functional programming or just functional programming in general.
       | its a useful tool with a time and a place, I don't get all the
       | "currying hate."
        
       | tenaciousDaniel wrote:
       | It's funny, I learned about currying back when I was first
       | learning Javascript and programming in general. That was 10 years
       | ago, and not _once_ in my 10 years as a professional programmer
       | have I ever needed to curry. Maybe I 've been missing out, but I
       | don't feel like I have.
        
       | guntars wrote:
       | A word of caution - using functional programming principles in a
       | language that is not optimized for it can result in awful
       | performance. In JavaScript, whenever you create a closure it's a
       | heap allocation. If you're doing that in a tight loop, it'll
       | completely dominate the time it takes to run your program.
        
         | avinassh wrote:
         | How do functional programming languages optimises these?
        
           | oweiler wrote:
           | I don't know about other languages, but in Kotlin these are
           | normally inlined, which means no allocation.
        
         | eurasiantiger wrote:
         | Yes. In JS it is best to avoid FP principles such as
         | immutability in hot code paths, the extra allocations and GCs
         | are not worth the cleanliness.
        
         | imbnwa wrote:
         | Redux is a good example of a functional pattern that makes
         | waaay more sense in a language with pattern matching, immutable
         | values, and ADTs built in. You have to really think about what
         | you're doing to scale Redux up with a large app in a JS runtime
         | and to avoid the boilerplate. Last time I used Redux with TS
         | the typings were not particularly helpful as well but that
         | may've improved.
        
         | brundolf wrote:
         | Are you speaking from experience or speculating? It's intuitive
         | that there would be some overhead, but the amount of overhead
         | could be anywhere from tiny to huge, especially given how
         | aggressive V8 is about optimizing certain things
        
       ___________________________________________________________________
       (page generated 2021-09-19 23:01 UTC)