使用 Ramda 存储临时值的模式

Pattern to store temporary values with Ramda

模式

我一直发现自己这样做,但我不确定这样做是否合适,或者我是否以错误的方式处理事情。

考虑以下几点:

const unfoldLast = curry(
  (pred, fn, init) => pipe(
    unfold(n => 
      (next => pred(n, next) && [n, next])(fn(n))
    ),
    last
  )(init)
);

具体来说,

n => (next => pred(n, next) && [n, next])(fn(n))

我读起来不太好。它是一个使用其闭包并立即被调用的匿名函数。

我希望它看起来像这样:

n => pred(n, fn(n)) && [n, fn(n)]

这行为完全相同,只是它运行 fn(n) 两次。

问题

我发现自己经常使用这种立即调用匿名函数的模式来 store 一个临时值。我不确定如何以易于阅读的方式做类似的事情。

我不确定是否有解决此问题的好方法。我发现我会根据我当前的需要在您正在做的事情和 call 的使用之间切换。

n => (next => pred(n, next) && [n, next])(fn(n))

可以改写为

n => call (
  (next) => pred (n, next) && [n, next],
  fn (n)
)

或相当于

n => call (
  (next = fn (n)) => pred (n, next) && [n, next]
)

有时我不使用 Ramda1,而不是将 call 定义为 (fn, ...args) => fn (...args),我会使用这个版本:(fn) => {with: (...args) => fn (...args)} 然后我可以将其用作 call (myFunction) .with ('some' , 'args')。但这仅在使用命名函数时才有用。

我非常喜欢纯表达式编码,在我的函数定义中不使用语句,只使用表达式。这就是导致这个问题的原因。如果你不介意包含一些语句,这也可以写成

n => {
  const next = fn(n)
  return pred (n, next) && [n, next]
}

1 免责声明:我是 Ramda 作者。

只是为了扩展上面的正确答案,您还可以通过提取一些位(并免费获得一些实用程序)使其更具可读性:

const tupleWith = curry((fn, x) => [x, fn(x)]);

您的展开迭代器函数将如下所示:

pipe(tupleWith(fn), unless(pred, F))

如果你不能改变 pred 的形状来接受一个数组,你总是可以用 apply(pred) 包裹它。