简体   繁体   English

如何使用ramda.js重构此代码?

[英]How do I refactor this code using ramda.js?

I'm using mithril.js and ramda.js . 我正在使用mithril.jsramda.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 . 因此,基本上我要遍历ctrl.itemsitem.policies只是返回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. 因此,如果一切顺利, R.allPass(item.policies)(item)给出的结果为true ,否则为false ,然后由我决定是否渲染li标签。

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. 因此,我想不要使用map,而是使用R.allPass filter掉项目,然后渲染出过滤后的数组。

I started fiddling around with a simple filter in ramda, but I cannot figure out how to achieve the result: 我开始在ramda中摆弄一个简单的过滤器,但是我不知道如何获得结果:

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. 它根本不排除任何项目。

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: 假设items包含这样的对象列表:

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] . 但是您将其视为仅适用于一个,就好像它可以用作filter :: (Item -> Boolean) -> [Item] -> [Item]

You need a way to transform your (Item -> Item -> Boolean) into a (Item -> Boolean) . 您需要一种将(Item -> Item -> Boolean)转换为(Item -> Boolean)

There is nothing built into Ramda to help with this, although perhaps Ramda should consider adding this, as it's occasionally useful. Ramda并没有内置任何功能来帮助解决此问题,尽管Ramda可能会考虑添加此功能,因为它偶尔会有用。 But one of the standard combinators 1 , known as W would do this: 但是,称为W的标准组合器1之一将执行此操作:

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 . 您可以在Ramda REPL上看到这一点。


1 There is a nice list of combinators in Avaq's gist . 1Avaq的要旨中,有很多组合器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM