繁体   English   中英

使用Ramda.js的无点函数组合

[英]Point-free Function Composition with Ramda.js

我使用Ramda.js作为选择器函数,以访问Redux存储中的数据。 我想要的是将我的选择器定义为不引用选择器操作state函数,例如:

const getUserName = path(['user', 'name']);

const name = getUserName({
  user: {
    name: 'Some Name'
  }
});

对于简单的选择器来说这很容易,但有时候组合选择器会成为一个问题。

这是一个示例,其中一些items需要解析,由对象上的id引用:

const getItemById = id => state => path(['items', id], state);

const getConnectedItemIds = obj => path(['items'], obj);

const getItemsFromObj = obj => state => {
    const ids = getConnectedItemIds(obj);
    return ids.map(id => getItemById(id)(state));
};

第一个函数可以很容易地表达而不参考state ,而第二个函数没有obj ,我认为这个函数称为无点样式。 但如何编写没有state的第三个函数?

我正在寻找如何使用Ramda重写第三个函数,还有关于此的规则和程序,例如(不知道它是否真实):

所有组合函数都需要将state作为最后一个参数才能在最终组合中将其拉出。

这里有很多好的建议。 可能最重要的是只有在提高可读性时才使用无点的建议,而不是单独作为目标。

我的回答确实使用了你的主要功能和你的一个助手的无点版本,但跳过另一个,我觉得可读性会受到影响。

 const getItemById = id => path(['items', id]); const getConnectedItemIds = prop ('items'); const getItemsFromObj = pipe ( getConnectedItemIds, map (getItemById), juxt ) const obj = {foo: 42, items: ['8', '17']} const state = {bar: 1, items: {'6': 'a', '8': 'b', '14': 'c', '17': 'd', '25': 'e'}} console .log ( getItemsFromObj (obj) (state) ) 
 <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script> <script>const {juxt, map, path, pipe, prop} = R </script> 

这里的重要功能是juxt ,它将一组函数应用于相同的值,返回结果数组。

这里getItemById通过删除state点从原始getItemById中简化,但是只要我知道这一点,只需要以可读性为代价才能实现这一点。 其他人对此提出了建议,所有这些都很好,但正如他们所指出的,没有一个像上面那样可读。 我的版本看起来像这样:

const getItemById = compose (path, flip (append) (['items']));
//  or              pipe (flip (append) (['items']), path);

我不认为它比其他答案中的建议更好或更差,但它们都不像阅读那么容易

const getItemById = id => path(['items', id]);

最后,如果那些辅助函数没有在别处使用,我认为它实际上可以提高内联它们的可读性:

const getItemsFromObj = pipe (
  prop ('items'), 
  map (id => path(['items', id])), 
  juxt
)

注意 ,虽然我没有在这里使用它,但我确实喜欢propOr([], 'items')对于getConnectedItemIdspropOr([], 'items')的建议。 它彻底消除了一个潜在的失败点。

我认为你仍然可以用无点的方式编写它,可读性,然而,有点妥协..希望它有帮助:)

 /** * @param {string} id * @param {Object<string, *>} state **/ const getItemById = R.useWith(R.prop, [ R.identity, R.prop('items'), ]); const getItemsFromObj = R.useWith(R.flip(R.map), [ R.pipe(R.prop('items'), R.map(getItemById)), R.applyTo, ]); const items = { 1: { id: 1, title: 'Hello World' }, 2: { id: 2, title: 'Hello Galaxy' }, 3: { id: 3, title: 'Hello Universe' }, }; const state = { items }; // this should only take 'world' and 'universe'; console.log( 'result', getItemsFromObj({ items: [1, 3] }, state), ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script> 


笔记:

  1. Ramda函数都是咖喱,所以不需要在尾位置申报参数: obj => path(['items'], obj); 等于path(['items']);
  2. 无点有助于编写小型和集中的函数,但它应该与组合可读性相平衡

我喜欢无点风格。 我认为这会迫使你对功能的设计三思而后行,这总是一件好事。 但它永远不应该是一个目标。 只有在有意义的时候才使用它。

这个功能已经足够好了:

const getItemById = id => state => path(['items', id], state);

我唯一的建议是使用curry

const getItemById = curry((id, state) => path(['items', id], state));

你可以把它转换成无点的风格,但我不认为它实际上是值得的:

const getItemById = useWith(path, [pair('items'), identity]);

让我们回到你的问题。

我们有这两个功能:

const getItemById = curry((id, state) => path(['items', id], state));
const getConnectedItemIds = propOr([], 'items');

你可以像这样设计一个getItemsFromObj pointfree样式:

const getItemsFromObj = useWith(flip(map), [getConnectedItemIds, flip(getItemById)]);

或者您也可以简单地做:

const getItemsFromObj = curry((obj, state) => {
  const ids = getConnectedItemIds(obj);
  const idFn = flip(getItemById)(state);
  return map(idFn, ids);
});

我会推荐哪个版本? 我不知道; 这里有几点想法:

  1. 你感觉自然吗?
  2. 你的团队与FP有什么关系? 你能训练他们吗? 如果他们刚刚开始就去
  3. 在六个月内,您会觉得哪个版本更舒服?

我建议的一件事是你熟悉Hindley-Milner型系统。 这绝对是投入时间的好时机。

如果你没有采用无点风格,不要让任何人告诉你你没有正确地进行函数式编程。

它可以使它既短又无点,但我不确定它是否比使用变量的函数更具可读性。

const getItemsFromObj = R.useWith(R.props, [R.prop('items'), R.prop('items')])

我这里没有使用你的getItemById ,因为这个案例非常适合R.props 如果你真的想要使用两个原始函数,你可以这样写。

const getItemsFromObj = R.useWith(
  R.flip(R.map), [getConnectedItemIds, R.flip(R.uncurryN(2, getItemById))]
)

需要翻转和取消将getItemById函数参数从id -> state -> value转换为state -> id -> value

暂无
暂无

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

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