在管道中重用变量的功能方式 [英] Functional way of re-using variables in a pipe

查看:72
本文介绍了在管道中重用变量的功能方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

与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的

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆