我正在尝试使用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有一组函数来处理嵌套属性。在您的情况下,我们可以组合pathEq
和any
:
pathEq
返回true
如果一个属性在给定的路径等于给定的值。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)
但我发现这远不如其他建议好读。我就不麻烦了。