函数组合的可读性
Readability for function composition
我正在尝试使用 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);
}
两次尝试都得到了正确的结果,这个问题完全是从函数式编程的角度提出的,因为我是这个领域的新手,想知道哪个尝试比另一个更有利,希望这个问题不会因为意见而被关闭based,我真心认为这不是基于意见,而是寻求FP世界的行业实践。
除了我所做的两次尝试,也欢迎提供任何替代方案,谢谢!
至少在我看来,您的两种解决方案似乎都有些矫枉过正。
在不使用任何库的情况下,解决方案可以像这样简单,例如:
const isAuthor = (name, articles) => articles.some((article) => article.author.name === name)
函数式编程很酷,但这并不意味着你应该让事情变得不必要的复杂。
从您的建议来看,第一个似乎比第二个更具可读性。
将 Ramda 视为一种工具,它可以帮助您以某种方式编写代码,而不是决定您如何编写代码的工具。 Ramda(免责声明:我是创始人之一)允许您使用漂亮的组合和管道以更具声明性的方式编写。但这并不意味着您需要在所有可能的地方使用它。
来自 tuomokar 的简单 vanilla 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
作为 prop
内置于 Ramda 中,您的 names
可以写成 map (path (['author', 'name']))
。
我们可以自己或使用像 http://pointfree.io/ 这样的工具来消除这一点。它可能看起来像这样:
const isAuthor = compose ((o (__, map (path (['author', 'name'])))), contains)
但我发现它的可读性远不如其他任何建议。我不会打扰。
Ramda 有一组函数可以处理嵌套属性。在你的情况下,我们可以结合 pathEq
和 any
:
pathEq
returns true
如果给定路径的 属性 等于给定值。
any
对列表的每个元素应用谓词函数,直到满足为止。
isAuthor
函数首先获取名称,然后 returns 获取列表的函数:
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
我正在尝试使用 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);
}
两次尝试都得到了正确的结果,这个问题完全是从函数式编程的角度提出的,因为我是这个领域的新手,想知道哪个尝试比另一个更有利,希望这个问题不会因为意见而被关闭based,我真心认为这不是基于意见,而是寻求FP世界的行业实践。
除了我所做的两次尝试,也欢迎提供任何替代方案,谢谢!
至少在我看来,您的两种解决方案似乎都有些矫枉过正。
在不使用任何库的情况下,解决方案可以像这样简单,例如:
const isAuthor = (name, articles) => articles.some((article) => article.author.name === name)
函数式编程很酷,但这并不意味着你应该让事情变得不必要的复杂。
从您的建议来看,第一个似乎比第二个更具可读性。
将 Ramda 视为一种工具,它可以帮助您以某种方式编写代码,而不是决定您如何编写代码的工具。 Ramda(免责声明:我是创始人之一)允许您使用漂亮的组合和管道以更具声明性的方式编写。但这并不意味着您需要在所有可能的地方使用它。
来自 tuomokar 的简单 vanilla 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
作为 prop
内置于 Ramda 中,您的 names
可以写成 map (path (['author', 'name']))
。
我们可以自己或使用像 http://pointfree.io/ 这样的工具来消除这一点。它可能看起来像这样:
const isAuthor = compose ((o (__, map (path (['author', 'name'])))), contains)
但我发现它的可读性远不如其他任何建议。我不会打扰。
Ramda 有一组函数可以处理嵌套属性。在你的情况下,我们可以结合 pathEq
和 any
:
pathEq
returnstrue
如果给定路径的 属性 等于给定值。any
对列表的每个元素应用谓词函数,直到满足为止。
isAuthor
函数首先获取名称,然后 returns 获取列表的函数:
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