函数组合的可读性



我正在尝试使用Ramda练习函数组合,但想知道它是否被过度使用,需要一些建议。

给定下面的对象

const articles = [
{
title: 'Everything Sucks',
url: 'http://do.wn/sucks.html',
author: {
name: 'Debbie Downer',
email: 'debbie@do.wn'
}
},
{
title: 'If You Please',
url: 'http://www.geocities.com/milq',
author: {
name: 'Caspar Milquetoast',
email: 'hello@me.com'
}
}
];

创建一个布尔函数,表示是否有某个人写了这些文章。

函数调用示例

isAuthor('New Guy', articles) // should return false
isAuthor('Debbie Downer', articles) // should return true

我的解决方案

首先,我创建一个函数来获取作者的名字,如下所示

const get = _.curry(function(x, obj) { return obj[x]; });
const names = _.map(_.compose(get('name'), get('author'))); // ['Debbie Downer', 'Caspar Milquetoast']

现在我有一个可以使用的函数names,我将尝试构造isAuthor函数,下面是我的两个尝试

尝试1:没有合成

const isAuthor = function(name, articles) {
return _.contains(name, names(articles))
};

尝试2合成

const isAuthor = function(name, articles) {
return _.compose(
_.contains(name), names
)(articles);
}

两种尝试都有正确的结果,这个问题完全是从函数式编程的角度提出的,因为我对这个领域完全陌生,想知道哪种尝试比另一种更有利,希望这个问题不会因为基于意见而关闭,我真诚地认为这不是基于意见,而是寻求FP世界的工业实践。

也请随意提供任何替代方案,而不是我所做的两个尝试,谢谢!

Ramda有一组函数来处理嵌套属性。在您的情况下,我们可以组合pathEqany:

  1. pathEq返回true如果一个属性在给定的路径等于给定的值。
  2. any对列表中的每个元素应用谓词函数,直到满足为止。

isAuthor函数首先接受一个名称,然后返回一个接受列表的函数:

const {compose, any, pathEq} = R;
const isAuthor = compose(any, pathEq(['author', 'name']));
isAuthor('Debbie Downer')(articles);
//=> true
isAuthor('John Doe')(articles);
//=> false

但这并不一定比:

const {curry} = R;
const isAuthor = curry((x, xs) => xs.some(y => y?.author?.name === x));

isAuthor('Debbie Downer')(articles);
//=> true
isAuthor('John Doe')(articles);
//=> false

至少在我看来,你的两个解决方案似乎都是小题大做。

不使用任何库,解决方案可以像这样简单,例如:

const isAuthor = (name, articles) => articles.some((article) => article.author.name === name)

函数式编程很酷,但这并不意味着你应该把事情弄得不必要的复杂。

从你的建议来看,第一个似乎比第二个更具可读性。

把Ramda看作是一个帮助您以某种方式编写代码的工具,而不是指示您如何编写代码的工具。Ramda(免责声明:我是创始人之一)允许您使用良好的组合和管道,以更具声明性的方式进行编写。但这并不意味着你需要在任何地方使用它。

来自tuomokar的简单的JS答案可能就是你所需要的,但是Ramda确实有一些工具可以使它看起来更容易读。

我们可以这样写:

const isAuthor = (name) => (articles) => 
includes (name) (map (path (['author', 'name'])) (articles))
const articles = [{title: 'Everything Sucks',url: 'http://do.wn/sucks.html', author: {name: 'Debbie Downer',email: 'debbie@do.wn'}}, {title: 'If You Please', url: 'http://www.geocities.com/milq', author: {name: 'Caspar Milquetoast', email: 'hello@me.com'}}]
console .log (isAuthor ('New Guy') (articles))
console .log (isAuthor ('Debbie Downer') (articles))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script>const {includes, map, path} = R                                  </script>

请注意,您的get被内置到Ramda作为prop,而您的names可以写成map (path (['author', 'name']))

我们可以自己做,或者使用http://pointfree.io/这样的工具。它可能看起来像这样:

const isAuthor = compose ((o (__, map (path (['author', 'name'])))), contains)

但我发现这远不如其他建议好读。我就不麻烦了。

相关内容

  • 没有找到相关文章

最新更新