在管道中重用变量的功能方式 [英] Functional way of re-using variables in a pipe
问题描述
与ramda一起使用javascript和typescript中的函数式编程,我经常发现自己编写如下代码:
Using functional programming in javascript and typescript together with Ramda, I often find myself writing code like:
const myFun = c => {
const myId = c.id
const value = pipe(
getAnotherOtherPropOfC,
transformToArray,
mapToSomething,
filterSomething,
// ... N other transformations
// ok now I need myId and also the result of the previous function
chainMyIdWithResultOfPreviousFunction(myId)
)(c)
return value
}
注意创建const myId
如何破坏无点样式.我想写myFun
,所以不需要显式的c
.所以像这样:
const myFun = pipe(....)
Notice how creating a const myId
breaks point-free style. I'd like to write myFun
so that there's no need to explicit c
. So something like:
const myFun = pipe(....)
我想知道是否有一种更实用,更易读的方式来做这样的事情.
I was wondering if there's a more functional and readable way of doing things like this.
推荐答案
可以完成吗?当然. 应该完成吗?还不清楚.
Can it be done? Sure. Should it be done? It's not so clear.
以下是使用lift
的上述版本的无要点版本:
Here is a point-free version of the above, using lift
:
const getAnotherOtherPropOfC = prop ('x')
const transformToArray = split (/,\s*/)
const mapToSomething = map (Number)
const filterSomething = filter (n => n % 2 == 1)
const square = (n) => n * n
const chainMyIdWithResultOfPreviousFunction = (id) => (arr) => `${id}: [${arr}]`
const myFun = lift (chainMyIdWithResultOfPreviousFunction) (
prop ('id'),
pipe(
getAnotherOtherPropOfC,
transformToArray,
mapToSomething,
filterSomething,
map (square)
)
)
console .log (
myFun ({id: 'foo', x: '1, 2, 3, 4, 5'}) // => 'foo: [1,9,25]'
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script> const {prop, split, map, filter, lift, pipe} = R </script>
lift
比Ramda的 useWith
提供了制作无点解决方案的方法,通常是以牺牲可读性为代价的.)lift
在应用于函数时与converge
重叠,但设计用于一元函数,其中converge
处理多发性硬化症.
lift
is a more FP-standard function than Ramda's converge
(which together with useWith
offer ways to make point-free solutions, often at the expense of readability.) lift
overlaps with converge
when applied to functions, but is designed for unary functions, where converge
handles polyadic ones.
这并不可怕.但是与原始版本相比,它唯一的优势在于它是无点的.而且,如果您尝试将其扩展到该管道中的中间功能,它将变得非常丑陋.
This is not horrible. But the only advantage it has over the original is that it's point-free. And if you were to try to extend this to intermediate functions in that pipeline, it would get downright ugly.
我的观点是,无意义的代码有时会导致代码更简洁,更易于阅读和维护.但是,如果没有这样做,就没有理由免费.
My take is that point-free can at times lead to cleaner, easier-to-read, and easier-to-maintain code. But there is no reason to go point-free when it doesn't do so.
并不是说,无指向性在本质上比有指向性的代码更具功能性.我认为这个想法是从其他语言开始的一种Haskell嫉妒开始的. Haskell被认为是一种理想的FP语言,并且碰巧是一种无点自然出现的语言.但这至少是偶然的.
It's not that point-free is inherently more functional than pointed code. I think this idea starts as a sort of Haskell-envy from other languages. Haskell is held up as an idealized FP language, and it happens to be a language in which point-free comes naturally. But that's at least partially coincidental.
我的标准示例是const sum = reduce(add, 0)
比const sum = (xs) => xs.reduce(add, 0)
更干净,更易理解.它还非常清楚地说明了与const product = reduce(multiply, 1)
或const all = reduce(and, true)
的相似之处.但是随着您变得越来越复杂,或者当您需要重用中间计算时(如Bergi所指出的那样),无点代码通常会成为一种负担.
My standard example is that const sum = reduce(add, 0)
is cleaner and more comprehensible than const sum = (xs) => xs.reduce(add, 0)
. It also makes extremely clear the parallels with const product = reduce(multiply, 1)
or const all = reduce(and, true)
. But as you get more complex, or when you need to reuse an intermediate calculation (as Bergi pointed out), point-free code often becomes a liability.
对于这个版本是否是对原始版本的改进,我没有真正的电话.如果是这样,那只是个小问题.进一步携带它会大大降低可读性.
I don't have a real call here about whether this version is an improvement on the original. If so, it's only a minor one. Carrying it further would significantly degrade the readability.
这篇关于在管道中重用变量的功能方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!