gpt4 book ai didi

javascript - 将 R.filter 和 R.map 重构为 pointfree 风格的 R.reduce

转载 作者:行者123 更新时间:2023-11-29 19:16:27 24 4
gpt4 key购买 nike

我开始学习了Ramda.js和函数式编程,并且对使用 pointfree 编程风格的函数组合非常感兴趣,但是我很难理解其中的一些,我希望有人可以帮助说明:

假设我有一个人员列表 - 我只想获取年龄在 13-19 岁(青少年)之间的人员。然后,我想将每个人映射到该人的 getName() 方法(如果存在)的返回值,或者映射到他们的 name 属性。然后,我想对名称调用 .toUpperCase()

如果我使用常规的 JS 原型(prototype)方法,我不会使用 Array.prototype.filter 来获取青少年用户,然后再使用 Array.prototype.map。出于性能原因,我会使用 Array.prototype.reduce,它的主体将由一个条件来保护,该条件检查每个迭代项目是否满足青少年的标准。这样,我就少了一次迭代。 Elijah Manor has an article about this on his blog .

这是我使用 R.filterR.map 得到的 pointfree Ramda 代码(按预期工作):

var people = [
{ name: 'Bob', gender: 'male', age: 22 },
{ name: 'Jones', gender: 'male', age: 15 },
{ name: 'Alice', gender: 'female', age: 19 },
{ name: 'Carol', gender: 'female', age: 32 },
{ name: 'Odu', gender: 'male', age: 25 },
{ name: 'Fred', gender: 'male', age: 55 },
{ name: 'Nicole', gender: 'female', age: 29 },
{ getName: function() { return 'David' }, gender: 'male', age: 23 }
]

var getUpcasedTeenagerNames = R.pipe(
R.filter(
R.propSatisfies(R.both(R.lte(13), R.gte(19)), 'age')
),
R.map(
R.pipe(
R.ifElse(
R.propIs(Function, 'getName'),
R.invoker(0, 'getName'),
R.prop('name')
),
R.toUpper
)
)
)

getUpcasedTeenagerNames(people) // => ['JONES', 'ALICE']

我的问题是 - 我将如何重写上述算法的以下原生版本以使用 pointfree Ramda.js?

var getUpcasedTeenagerNames = function(people) {
return people
.reduce(function(teenagers, person) {
var age = person.age
if (age >= 13 && age <= 19) {
var name
if (typeof (name = person.getName) === 'function') {
name = name()
} else {
name = person.name
}
teenagers.push(name.toUpperCase())
}
return teenagers
}, [])
}

我试过用 R.scan 来做,也看过 R.reducedR.when 但我很害怕我可能有点漏掉了重点。

为了您的方便,我在 Ramda REPL 中包含了这段代码:http://goo.gl/6hBi5k

最佳答案

首先,我会以不同的方式分解问题。我会使用 Ramda 的 R.__ 占位符来填充 R.lteR.gte 的第一个参数,以便它们更好地阅读。我喜欢用简单的下划线作为别名,所以这将显示为 R.both(R.gte(_, 13), R.lte(_, 19)),我发现它更具可读性。然后我会分离出在一个人身上找到名字的功能。这显然是一段独立的代码,将其取出可以使主要代码更具可读性。

最后,重要的是,如果你了解一点 Transducers ,您将学到一个技巧,无需担心初始技术中可能出现的性能问题的中间集合。

var _ = R.__;
var findName = R.ifElse(
R.propIs(Function, 'getName'),
R.invoker(0, 'getName'),
R.prop('name')
);

var getUpcasedTeenagerNames = R.into([], R.compose(
R.filter(
R.propSatisfies(R.both(R.gte(_, 13), R.lte(_, 19)), 'age')
),
R.map(R.pipe(findName, R.toUpper))
));

getUpcasedTeenagerNames(people); //=> ["JONES", "ALICE"]

现在我根本不会担心性能问题,除非我发现性能问题并表明这部分代码是罪魁祸首。但如果我有,那么我可以通过使用转换器来修复它,并且由于 mapfilter 已经可以工作了,我需要做的就是切换我的合成方向(这里通过从管道更改为撰写)并用 into([]) 包装它.

如果你有兴趣,这里是an article在 Ramda 中的用户传感器上,以及 another good intro到换能器。

如果我有一点时间,我会看看我是否可以将您的代码转换为免积分的解决方案,但请不要对免积分进行迷信。这是一个有用的技术在某些情况下,但我们不应该被迫在它不容易适应的地方使用它。

关于javascript - 将 R.filter 和 R.map 重构为 pointfree 风格的 R.reduce,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34992263/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com