Reputation: 827
I'm using mithril.js
and ramda.js
. I have the following code in mithril:
return m('ul.list-inline.text-center', [
ctrl.items.map(item => R.allPass(item.policies)(item) ? m('li', m('a', {
href: item.uri,
config: m.route
}, item.name)) : null)
]);
So basically I'm iterating over ctrl.items
and item.policies
is just an array of simple functions returning true / false
. Therefore, R.allPass(item.policies)(item)
gives me either true
if everything passes or false
otherwise and then this decides whether to render li
tag or not.
So instead of this functionality, I thought it would be better to create this more functional way as I will be able to reuse the code. So instead of map, I thought I would filter
down the items using that R.allPass
and then just render out the filtered array instead.
I started fiddling around with a simple filter in ramda, but I cannot figure out how to achieve the result:
var filterItems = R.filter(
R.pipe(
R.prop('policies'),
R.allPass
)
);
This just returns the full array. It doesn't exclude any items at all.
Upvotes: 1
Views: 131
Reputation: 50807
Well, from what I can make of your types, the issue is that you're expecting a function to do double-duty.
Assuming items
contains a list of objects such as this:
const items = [
{
name: 'foo',
val: 13,
policies: [
obj => obj.val > 10,
obj => obj.val < 20,
obj => obj.val % 2 == 1,
]
},
{
name: 'bar',
val: 14,
policies: [
obj => obj.val > 10,
obj => obj.val < 20,
obj => obj.val % 2 == 1,
]
}
];
then this:
R.pipe(
R.prop('policies'),
R.allPass
)
will have a type something like:
const testPolicies = R.pipe(
R.prop('policies'), // :: Item -> [(Item -> Boolean)]
R.allPass // :: [(Item -> Boolean)] -> Item -> Boolean
) // => :: Item -> Item -> Boolean
You need to pass two copies of your item to this function to get it to return a boolean. But you treat it as though it would work with just one, as though it could serve as an input to filter :: (Item -> Boolean) -> [Item] -> [Item]
.
You need a way to transform your (Item -> Item -> Boolean)
into a (Item -> Boolean)
.
There is nothing built into Ramda to help with this, although perhaps Ramda should consider adding this, as it's occasionally useful. But one of the standard combinators1, known as W
would do this:
const W = f => x => f(x)(x);
You could then use it like this:
R.filter(W(testPolicies), items); //=>
// {
// name: 'foo',
// val: 13,
// policies: [
// obj => obj.val > 10,
// obj => obj.val < 20,
// obj => obj.val % 2 == 1,
// ]
// }
You can see this in action on the Ramda REPL.
1 There is a nice list of combinators in Avaq's gist.
Upvotes: 1