3 ms·
Does Typescript have a facility to support partial function application? Say I have a function of arity 4, and want to bind / partially apply (some might say "
by Roboprog 10y ago
Does Typescript have a facility to support partial function application?
Say I have a function of arity 4, and want to bind / partially apply (some might say "inject") 2 arguments to it to create a function of arity 2, can TS infer the types of the remaining arguments, or, that the result is a function at all???
I use partial function application MUCH more than classes in the JS code that I write. There just seems to be less to need all that "taxonomy" related refactoring.
"Stop Writing Classes", "Executioner" in "The Kingdom of Nouns" (not!), and all that sort of thing :-)
- Roboprog 10y agoFor those of you unfamiliar with partial function application, it's a good way to replace many classes that consist of nothing other than a single "do the work" method and a constructor or setters for the configuration/dependencies with a single function. You put the configuration / dependency parameter(s) first, and the more "volatile" parameter(s) last. Rather than having a constructor call, you partially apply the things you want pre-bound (config, deps) to create a new shorter function that acts as the "do it!" method. E.g. - write a function to send emails. Put the "reply to" parameters first. Partially apply that data. Use the resulting function to send emails to specific people. Bind on the distribution list name argument. Use that function to send alerts to those recipients. Bind on the content of an alert. Use that to send an alert when needed, without having to come up with any of the input, just the 0-argument function. Overloading, alternate constructors, subclasses??? Screw that. As long as the parameter order is reasonable (least to most volatile), there is seldom anything to be "refactored" "Currying" just means that you apply a single argument at a time, until you get down to an "arity 1" function, after which the final argument runs the original function with the last remaining argument, rather than returning an "arity 0" function. Here is an example library that does A LOT of currying: http://ramdajs.com/docs/ http://ramdajs.com/docs/ If I apply/bind a function to my higher order function, is that dependency injection, or subclassing? Who cares. I like arity 0 functions. They make nice event handlers. I have been gradually converting to Javascript for the last 8 years. My paradigm has definitely shifted. I know how miserable static OOP is, and won't be going to my grave not knowing :-) (here's the quote: https://www.facebook.com/groups/nodejsis/permalink/1429400523804671/ https://www.facebook.com/groups/nodejsis/permalink/142940052...)
- Roboprog 10y agoI suppose this is orthogonal to compile time types, but I had to write my own utility to support PFA "decoration" of functions. It of course knows nothing about the number or type of arguments in the original function. (I usually write JSDoc comments about resulting intermediate functions if they leave the nest) For TS to do this, the compiler would need to supply the "apply"/"bind" feature and track that a function goes in, and the list of argument types, so it can check what is applied and track the types of any remaining arguments. Doable, but if it's not built into the compiler, I have to start running a transpile process that buys very little for much of my code.
- andrewstuart 10y agoI want to hear more about this technique. I will email you.
- Roboprog 10y agoConsider this: http://ramdajs.com/docs/#sort http://ramdajs.com/docs/#sort Say I want to sort a list of objects/records that have a "name" field by name. I can compose some functions to do this, and use the resulting function where needed (regardless of the input object list "type(s)", as long as it/they quacks back with a "name" property/field). I'm going to assign some functions to intermediate symbols, but that's not strictly required, since functions are an expression/value like many other things. var name_comp = function( l, r ) { return l < r } var sort_by_name = R.sort( name_comp ) // alternatively: ... = R.sort( function ( l, r) { return l < r } ) ... var old_list = [ { name: 'Middle', foo: 'bar' }, { name: 'Zero', bluk: 'phooey' }, { name: 'Alpha', answer: 42 } ] ... var new_list = sort_by_name( old_list ) // ... Alpha ... Middle ... Zero ... In general, the curried arguments can be primitives and objects, as well as functions. The Ramda library is primarily geared around taking common "collections" types of operations and chaining them together. It has other FP "mathy" stuff that I still have not got my head around yet, as well.
- Too 10y agoSounds like function foo(f: function<T1, T2>(T1 x, T2 y), bindY: T2) { return (x) => f(x, bindY); } This will be type safe and return a function<T1>(T1 x). (Disclaimer to typos and erros for typing on my phone)
- Roboprog 10y agoSimilar to that, yes - you have a higher order function, "foo" in this case, that accepts a function as an argument, and returns another function. FWIW, you want to have an operation to bind the first (or first N) formal parameter to a value, and you want to be able to have an arbitrary number of remaining parameters. Whatever facility would be in place needs to allow for N remaining formal parameters, of various types, not merely do the ("generic" / templated / type-parameter) recipe for one additional parameter. I am not a Haskell or F# programmer, but maybe the TS team wants to look at what those languages do.
- andrewstuart 10y ago>>> "Stop Writing Classes", "Executioner" in "The Kingdom of Nouns" (not!), and all that sort of thing :-) Are these references to blog posts?
- Roboprog 10y agoSomething like that. https://www.youtube.com/watch?v=o9pEzgHorH0 https://www.youtube.com/watch?v=o9pEzgHorH0 http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom... https://www.youtube.com/watch?v=rhV6hlL_wMc https://www.youtube.com/watch?v=rhV6hlL_wMc (in particular, the quote just after 17:00)