首页 > 解决方案 > Functional way of re-using variables in a pipe

问题描述

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
}

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.

标签: javascriptfunctional-programmingramda.js

解决方案


可以做到吗?当然。 应该这样做吗?这不是很清楚。

这是上述的无点版本,使用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 更符合 FP 标准的函数converge(它与useWith提供无点解决方案的方法一起,通常以牺牲可读性为代价。) 与应用于函数时lift重叠,但设计用于处理多元函数的一元函数。convergeconverge

这并不可怕。但它与原版相比的唯一优势是它是无点的。如果你试图将它扩展到该管道中的中间函数,它会变得非常难看。

我的看法是,无点有时会导致代码更清晰、更易于阅读和更易于维护。但是,如果不这样做,就没有理由去无点。

这并不是说无指向代码本质上比指向代码更实用。我认为这个想法始于对其他语言的一种 Haskell 嫉妒。Haskell 被认为是一种理想化的 FP 语言,而它恰好是一种自然而然地出现无点的语言。但这至少部分是巧合。

我的标准示例是const sum = reduce(add, 0)const sum = (xs) => xs.reduce(add, 0). 它也非常清楚地与const product = reduce(multiply, 1)or的相似之处const all = reduce(and, true)。但是当您变得更加复杂,或者当您需要重用中间计算时(正如 Bergi 指出的那样),无点代码通常会成为一种负担。

关于这个版本是否是对原版的改进,我在这里没有真正的电话。如果是这样,那只是小事。进一步携带它会显着降低可读性。


推荐阅读