-->

How to rewrite this in terms of R.compose

2019-07-20 13:35发布

问题:

var take = R.curry(function take(count, o) {
    return R.pick(R.take(count, R.keys(o)), o);
});

This function takes count keys from an object, in the order, in which they appear. I use it to limit a dataset which was grouped.

I understand that there are placeholder arguments, like R.__, but I can't wrap my head around this particular case.

回答1:

This is possible thanks to R.converge, but I don't recommend going point-free in this case.

//  take :: Number -> Object -> Object
var take = R.curryN(2,
                    R.converge(R.pick,
                               R.converge(R.take,
                                          R.nthArg(0),
                                          R.pipe(R.nthArg(1),
                                                 R.keys)),
                               R.nthArg(1)));

One thing to note is that the behaviour of this function is undefined since the order of the list returned by R.keys is undefined.



回答2:

I agree with @davidchambers that it is probably better not to do this points-free. This solution is a bit cleaner than that one, but is still not to my mind as nice as your original:

// take :: Number -> Object -> Object
var take = R.converge(
    R.pick, 
    R.useWith(R.take, R.identity, R.keys), 
    R.nthArg(1)
);

useWith and converge are similar in that they accept a number of function parameters and pass the result of calling all but the first one into that first one. The difference is that converge passes all the parameters it receives to each one, and useWith splits them up, passing one to each function. This is the first time I've seen a use for combining them, but it seems to make sense here.

That property ordering issue is supposed to be resolved in ES6 (final draft now out!) but it's still controversial.


Update

You mention that it will take some time to figure this out. This should help at least show how it's equivalent to your original function, if not how to derive it:

var take = R.converge(
    R.pick, 
    R.useWith(R.take, R.identity, R.keys), 
    R.nthArg(1)
);
    // definition of `converge`
(count, obj) => R.pick(R.useWith(R.take, R.identity, R.keys)(count, obj), 
        R.nthArg(1)(count, obj));
    // definition of `nthArg`
(count, obj) => R.pick(R.useWith(R.take, R.identity, R.keys)(count, obj), obj);
    // definition of `useWith`
(count, obj) => R.pick(R.take(R.identity(count), R.keys(obj)), obj);
    // definition of `identity`
(count, obj) => R.pick(R.take(count, R.keys(obj)), obj);

Update 2

As of version 18, both converge and useWith have changed to become binary. Each takes a target function and a list of helper functions. That would change the above slightly to this:

// take :: Number -> Object -> Object
var take = R.converge(R.pick, [
    R.useWith(R.take, [R.identity, R.keys]), 
    R.nthArg(1)
]);


标签: ramda.js