-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Viability of achieving this in userland libraries #45
Comments
Lodash's _.partial works pretty much like that (without some of the more advanced features you envision in the last example). const f = (a, b, c) => { console.log(a, b, c) }
const incomplete = _.partial(f, 1, _, 3)
incomplete(2)
// logs 1, 2, 3 there are also similar functions in other popular utility libraries.
IMO this is a big benefit of the operator. I practically never use the import {_, partial} from 'a-partial-application-library'
const plus2 = partial(plus, _, 2) is more cumbersome and arguably even less readable than your everyday const plus2 = _ => plus(_, 2) Also their static typing with TS/Flow often leaves much to be desired. |
Here is my proposal polyfill. It only supports partial application from left to right, just like in a functional programming language like Haskell or Elm. One could also write a /**
* @description Partial polyfill
* @author Amin NAIRI <https://github.com/aminnairi/>
* @version 1.0.0
* @example https://replit.com/@amin_nairi/LividEffectiveConversions#index.js
*/
const partial = (callback, ...initialArguments) => {
return (...additionalArguments) => {
const allArguments = [...initialArguments, ...additionalArguments];
if (allArguments.length >= callback.length) {
return callback(...allArguments);
}
return partial(callback, ...allArguments);
};
};
const add = partial((first, second) => {
return first + second;
});
const range = partial((from, to) => {
return [...Array(to - from + 1)].map((_, index) => {
return index + from;
});
});
const fromFiveTo = range(5);
const increment = add(1);
const decrement = add(-1);
console.log(fromFiveTo(10)); // [5, 6, 7, 8, 9, 10]
console.log(range(1, 5)); // [1, 2, 3, 4, 5]
console.log(add(2, 3)); // 5
console.log(increment(4)); // 5
console.log(decrement(0)); // -1 Not sure if this is really necessary to do partial application backward for an argument import {storageGet} from "./library/api/storage-get.mjs";
import {storageSet} from "./library/api/storage-set.mjs";
storageSet(localStorage, "search", "");
storageGet(localStorage, "search").whenOk(searchValue => console.log(searchValue));
storageGet(localStorage, "items").whenOk(storageSet(localStorage, "savedItems")); |
I'm by no means an expert on this, but I assume another huge benefit of this being part of the language is performance. Engines would be able to optimize partial application and/or pipes as if they were regular function calls, and not create the mess of intermediate functions. |
True, Rambda has a placeholder for doing that with Though this won't add too much overhead for most of the Web applications (to not say practically invisible for a non-power user) out there that do not have performance in mind, this can be critical for other range of domains like Gaming or Geolocation and such. In the end, achieving this in a userland library should be viable if there is no need for performance and we can achieve a pretty slick API with partial application and function composition. import {compose} from "partials/compose.mjs";
import {map, mapWithIndex} from "partials/map.mjs";
import {reduce} from "partials/map.mjs";
import {isModulo} from "partials/utils.mjs";
import {or} from "partials/logical.mjs";
const isValidFrenchCompanyIdentifier = compose([
map(compose([Number, or(0)])),
mapWithIndex(doubleIfOddIndex),
map(sumDigits),
reduce(sum),
isModulo(10)
]);
isValidFrenchCompanyIdentifier("732829320"); // true
isValidFrenchCompanyIdentifier("732829321"); // false |
@lazarljubenovic yes indeed! Terser could also know how to inline bound functions, since it can't know for sure that .bind() wasn't modified in the function prototype. When combining with pipelining, I think the performance cost of ? would disappear for most pipelining cases. As well as end the debate over on that proposal regarding first-argument vs curried. |
I don't know of how much of a niche this is, but the current proposal indeed would allow some light version of static metaprogramming without the need of a tool such as babel. Although one could argue that this is already achieved by using arrow functions to reorder/fix parameters (minus |
If we treat the pipelines proposal as a separate proposal and disregard the pipelines-related examples, I'm wondering if this proposal can entirely be achieved through libraries (and if not, then what what are the key issues that prevent it)
e.g. it should be possible to write a library that allows you to write
it may even be possible to support #5
and to support #7
Through these examples, I'm not saying that this proposal is not needed. Indeed some of the syntax clunkiness in a userland library would go away if this were a language feature. I'm just hoping that this leads to a discussion of he core language limitations that prevent this proposal from happening as a userland library, and to discuss if this proposal addresses those limitations well.
A discussion of how this can (even partially) be achieved in a userland library may also support development of this feature in transpilers (babel, typescript) and allow it to reach users faster.
The text was updated successfully, but these errors were encountered: