5 ms·
Currying is one of those things I haven't grokked completely. And, shit, I just used grok as a past tense verb... I'm not sure if i just haven't drunk enough k
by megaman22 9y ago
Currying is one of those things I haven't grokked completely. And, shit, I just used grok as a past tense verb...
I'm not sure if i just haven't drunk enough koolaid or if curriers are beyond the pale.
- emodendroket 9y agoIt's just a function returning another function. Like if you made a function that took x as its argument and returned a function that took y as its argument and added that to X and then you called it like add(2)(3). Or for a real world example check out $interpolate in angular 1.x.
- megaman22 9y agoI know all of these things... My brain just does not like the squishiness in most cases, or how silly and contrived most examples that I have seen are.
- emodendroket 9y agoWell they're contrived because a realistic example would have a ton of code having nothing to do with the concept
- megaman22 9y agoWell, in that case, they are of little more value than the equally contrived OOP examples we grew up with, with a base Fruit class, and Banana and Apple subclasses. Stupid examples are in many cases worse than no examples at all.
- emodendroket 9y agoWell I'm afraid I can't agree there. But like I said, the shower interpolate service is a real-world example and the purpose seems clear enough (why evaluate the string each time?)
- megaman22 9y agoIf there actually was an example where that measure of ceremony was involved and was worthwhile, I'm too dumb too have understood it.
- emodendroket 9y agohttps://docs.angularjs.org/api/ng/service/$interpolate https://docs.angularjs.org/api/ng/service/$interpolate
- posterboy 9y agoI'm sorry, "shower" can not be found in the featured article.
- emodendroket 9y agoWeird auto-correct issues from posting on the phone, but I meant to say "angular"
- 59nadir 9y agoLearn and use Haskell/OCaml/ReasonML/Elm and you'll get it. It's daft to use currying in languages that don't have a good base for supporting it.
- coltonv 9y agoHere's the simplest example I can come up with, and it's something I do all the time. I have an array of objects in my state. For this example we'll say they are Todos, and each one has three properties, id, name, and checked. I have a function `checkTodo` with the signature `checkTodo(id: string, event: InputEvent)` that I want to call if one of those Todos is checked. So say I'm using React. I can use arrow functions like this: todos.map((todo) => <input type="checkbox" onChange={ (event) => checkTodo(todo.id, event) } checked={ todo.checked } /> <label>{ todo.name } ) That's okay, but having arrow functions like that in JSX (which you'll have several of in a complex application) can get a bit unwieldy. Currying gives us another option that can be cleaner and avoids having to declare functions inside our render. If we change our method signature to this: `checkTodo = (id: string) => (event: InputEvent)` then we can write our JSX like this: todos.map((todo) => <input type="checkbox" onChange={ checkTodo(todo.id) } checked={ todo.checked } /><label>{ todo.name } ) It's a bit cleaner, and can make certain patterns a lot easier in the long run. For example, say we make a shared <Todo /> component like the one above which can be rendered both in a list, as above, or on it's own. In that case, it would be bad for the method signature that the Todo component expects to be the id and event, as the id wouldn't be necessary when we're not working with an array. Instead, currying means our Todo component can simply expect a function that takes in an InputEvent, and currying can move the other logic where it's needed. Does that make sense? If you don't know React I could rewrite this using native DOM calls.
- pwm 9y agoCurrying is essentially a trick to turn n-ary functions to unary functions so you can compose them. It also enables the creation of specific functions from generic ones by supplying arguments. Also, as functions can have functions as arguments it is the ultimate dependency injection pattern, if you’re familiar with the oop lingo.
- megaman22 9y agoI get the whole hole-in-the-middle functional dependency injection idea... The problem I frequently run into with this class of things is that people preach an unreasonable purity of thought with regard to the application of the technique, rather than just recognizing places it is useful and applying it there. Either one curries nothing, or one curries all the things. Monads are the fundamental fabric of the universe, or they are eldritch monoliths to worship, but not understand. Rarely is there the pragmatism applied to use these concepts where they make sense, and forego them for the simple where they do not.
- morgancmartin 9y agoI think that Clojure takes a sane approach to topics such as this one. I believe the "data first" approach tends to breed a pragmatic outlook when writing code and leaves behind all the proselytizing. Plus currying is built into the language, so there isn't any need for importing any special purpose libraries :) edit: a word
- bakul 9y agoThink of an array such as int x[5][10]. Here x is a two dim. array. Indexing it just once such as x[i], you get another array, a vector of 10 ints, which can be indexed further. So in a sense x[i] is a "curried" array! In general given an N dim. array, indexing it K (less than N) times you get an array of N-K dimensions. Now you can think of an array as a restricted function whose domain is 0..n x ... and range is some type. The same concept of "currying" applies to functions. That is, given a function of N arguments, if you provide K (less than N) arguments you get another function of N-K arguments. It is strange that many programming languages allow currying of arrays but not of functions!
- megaman22 9y agoThis is also, imo, a terrible example. I've almost never seen a serious application of 2D arrays, unless they were weirdly sparse, that actually used the 2D array notation... Almost always, it's flattened into a memory-efficient representation as a 1D array, with a lookup expression to convert x, y coordinates into an index.
- bakul 9y agoThe point was to give the OP an example he can hopefully wrap his head around the concept of currying.
- dmitriid 9y agoI find currying rarely useable in real life. Because you rarely need a fixed parameter to a function. And when you do it's solved in a better way by storing it in a state somewhere (even global variables will do in a pinch). The closest real world example I can think of right now is calling a webservice. Which is usually something like const baseUrl = 'https://some.tld' function callExternal(resourcePath, data) { fetch(baseUrl + resourcePath, data)... } // and then somewhere callExternal('/some/path', {some: data}) With currying you could do it like this: const baseFun = function(baseUrl, resourcePath, data) { fetch(baseUrl + resourcePath, data)... } const callExternal = baseFun('https://some.tld') // ^ you "pin" the first argument to always be 'https://some.tld' // and then somewhere callExternal('/some/path', {some: data}) I personally have had the need to write a curried function myself maybe twice over the course of the past 17 years.
- icebraining 9y agoYes, closures can be used to achieve a similar effect to currying. That said, they only work with functions you create yourself. If baseFun came from a library, you'd have to write an extra function just to close over baseUrl. Of course, one can wonder how many times can one usefully curry with external functions, but I think that's partially a result of not having currying syntax in the first place. For example, the fact that Ruby has blocks massively influences the typical design of its libraries, when compared to Python.