getify / fpo Goto Github PK
View Code? Open in Web Editor NEWFP library for JavaScript. Supports named-argument style methods.
License: MIT License
FP library for JavaScript. Supports named-argument style methods.
License: MIT License
Hi Kyle, love this lib!
I've thought about this in the past as well.
From that discussion, it seems that it'd be better for named curry to accept the argument names instead of just the number of arguments. This is my experience as well.
Otherwise, we may fall into the following trap. See that we expected 'z' but got 'k'.
function foo({ x,y,z }) { return x + y + z; }
var f = FPO.curry( {fn: foo, n: 3} );
f( {y: "b" } )()( {} )()( {x: "a", k: "c"} );
// "ab"
I like https://github.com/rjmk/named-curry implementation better. Although more verbose, it's safer and more flexible.
Also, you get "optional arguments" for free.
I'd be willing to write the code, but it is a breaking change.
I don't know if you care, but FPร is the name of an Austrian far-right party (see https://en.wikipedia.org/wiki/Freedom_Party_of_Austria). I figured you'd be interested in knowing ๐
Thanks for your work!
The approach to this library is interesting but I would like to hear from you, @getify: what was the reason(s) behind it?
Some of the points of interest you pointed out or I've noticed so far are:
compose({ fns: [] })
)It would be great for you to expand on the above and say what you think are the advantages and draw backs to this approach! Thanks
This looks great! I was wondering about how one could either use only the functions needed via tree shaking, or will the build process allow a custom build to be generated with a few functions?
Like Ramda: https://ramdajs.com/docs/#reduced
Want to add:
mapObj(..)
: like map(..)
but across all enumerable owned propertiesflatMapObj(..)
: like flatMap(..)
but across all enumerable owned propertiesfilterObj(..)
: like filter(..)
but across all enumerable owned propertiesreduceObj(..)
: like reduce(..)
but across all enumerable owned propertiestake(..)
: like in Ramdahead(..)
/ tail(..)
: like in Ramdamemoize(..)
: like in Ramdasequence(..)
to pipe(..)
reject(..)
to filterOut(..)
keep(..)
to filterIn(..)
(to mirror reject(..)
)Just got bitten by this quirk, but not sure if it's a bug or if we should leave it alone... thoughts?
function foo({x,y,z}) {
console.log(x,y,z);
}
var f = FPO.curryMultiple( {fn: foo, n: 3} );
f( {x:1,y:2} )( {x:4,z:3} );
What would you expect that output to be? I expected 1,2,3
since x
was already curried in the first call, but the result is that x:4
effectively overrides (re-curries?) the x:1
. That was surprising to me and caused me a bug.
Should named curry(..)
and curryMultiple(..)
restrict each input to only being specified once, the first time?
Partially related to #19
Inspired by the curryN(..)
from Ramda, these two would be loose-curried for a specified number of input functions. Allows lazy composition.
I'd like to use one of the functions in a project - but I don't want to depend on everything in this package.
For e.g. I'd like to use apply. Is my only option to copy-paste the relevant code? Are there / will there be "micro-lib" implementations of the functions in this package?
btw, I am aware that some build tools can detect unused code and remove it from the built bundle.
Some interesting things from Ramda to consider adding to FPO:
_arity(..)
is used to create a function with a proper .length
, from the results of utils like curry(..)
, etc
utils like flip(..)
will re-curry the function (in other words, assuming you always want currying)
I wanted to float an idea to take advantage of additional benefits from destructured object param function signatures... But first I want to include my thoughts on the pattern.
Here's an excerpt from an article I'm writing to explore the 'why' and trade-offs of this approach.
Destructured named object parameters is preferred to positional arguments in almost every case.
Inevitably, every design decision involves trade-offs. So, let me frame 2 priority goals, clarity and memorability, as more important than extreme DRY adherence.
undefined
argument).Exceptions: There are a few use cases which I agree should be positional: for example the copy
or mv
file commands are a good fit for positional arguments. (A low, fixed arity tends to make things easier.)
With that considered, I feel argument names which are abbreviated or single letters are unnecessarily harder to memorize. Learning names is hard enough, and abbreviations invite too much confusion (common example are all over, see unix /usr
path was originally UNIX source repository
, now it's UNIX system resources
, not user).
While it can be annoying typing accumulator
in every reduce, it's unambiguous as it's not clear that an abbreviation would be acc
instead of accum
. Perhaps a non-standard term is a better fit on that one, say results
or state
. (This bit is a discussion for later...)
If single letter variables should be avoided in code generally (except in constructs like loops,) why are they ok in parameters when the knock-on effect is a leaky abstraction passing weirdness to every invocation.
Please let me know how you feel about my take.
I really appreciate your time Kyle!
Thanks in advance!
Since property order is not guaranteed on Objects, does it even make sense to ask for their head or tail?
All four of FPO.compose(..)
, FPO.std.compose(..)
, FPO.pipe(..)
, and FPO.std.pipe(..)
do function composition where the output of the first function is pumped directly into the second one, not wrapped in an named-argument-object like { v: .. }
before being passed in. That means you can't really compose a sequence of functions that all expect named-arguments without unapply(..)
ing each subsequent function, such as:
var f = FPO.compose( {fns: [
FPO.unapply( {fn: FPO.flatten, props: ["v"]} ),
FPO.unapply( {fn: FPO.prop( {prop: 2} ), props: ["v"]} ),
FPO.prop( {prop: "x"} )
]} );
var obj = { x: [1,[2,3,4],[5,[6,7],8],9] };
f( {v: obj} );
// [5,6,7,8]
So should we add a xxxNamed(..)
-- I dunno what this naming should be! -- methods that does that wrapping. In other words, it would then be possible to do this:
var f = FPO.composeWHATEVER( {fns: [
FPO.flatten,
FPO.prop( {prop: 2} ),
FPO.prop( {prop: "x"} )
]} );
var obj = { x: [1,[2,3,4],[5,[6,7],8],9] };
f( {v: obj} );
// [5,6,7,8]
In the context of the philosophy of FPO -- it's all about named-argument aware behavior! -- it seems like these methods should exist. As a matter of fact, we could even make the case this is how the FPO.compose(..)
and FPO.pipe(..)
themselves should work by default, leaving only FPO.std.compose(..)
and FPO.std.pipe(..)
to work more "normally" without the wrapping.
So... thoughts?
Currently Istanbul seems to not work to do test coverage on this lib. Get that fixed.
Spun off from #3:
[For
flatten(..)
, which usesv
as its named argument...] what's the reasoning of not beingarr
in the first place?
Well, it's a judgement call and it could have gone either way. And TBH, I don't feel strongly that it has to be v
over arr
. But there's a bunch of other methods that take a single "value" argument to operate on, and in all those, we use v
. There are other methods that take an array and call it arr
, but those all take other params, too. For example, reduce(..)
takes v
for initial value and arr
for the array.
FTR, my thinking was, is flatten(..)
more like flatMap(..)
or is it more like pick(..)
or setProp(..)
? I leaned to the latter instead of the former only because with flatMap(..)
, the arr
is operated on by a fn
, but with pick(..)
, the value (object in this case) is the main focus, so it's called v
.
Of course, we have zip(..)
which names its two params arr1
and arr2
instead of v1
and v2
. I almost did that, for the same reason as v
for flatten(..)
, but then I thought that v1
and v2
might be slightly confusing as "version 1" / "version 2".
So, I'm open to debate here, would like feedback. Should we:
flatten(..)
to use arr
instead of v
?zip(..)
to use v1
/ v2
instead of arr1
/ arr2
?A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.