Ramda selfComposeWhile
Ramda selfComposeWhile
问题:
我正在学习函数式编程
开个玩笑,还有……
我有一个辅助函数,它一遍又一遍地与自身组合一个函数,直到满足某些条件。就像 f(f(f(f(f(f(f(x)))))))
或 compose(f,f,f,f,f,f,f)(x)
,除了它会一直运行,除非被告知停止。
我实现它的方式,它真的不像合成(而且也许无论如何这里使用的词都是错误的)
这是我目前的解决方案:
const selfComposeWhile = curry(
(pred, fn, init) => {
let prevVal = null;
let nextVal = init;
while(prevVal == null || pred(prevVal, nextVal)){
prevVal = nextVal;
nextVal = fn(nextVal);
}
return nextVal;
}
);
这里正在使用中:
const incOrDec = ifElse(gt(30), inc, dec);
console.log(
selfComposeWhile(lt, incOrDec, 0)
); // -> 29
我不想使用递归,因为 JavaScript 没有正确的尾递归,而且这个网站的同名 (Stack Overflow) 是我如何使用它的真正问题。
没有什么错误,但我一直在尝试通过将它们应用于虚拟问题来学习函数式编程技术,这是我为数不多的几个地方之一代码以绝对必要的方式脱颖而出。
我也有
useWith(selfComposeWhile, [pipe(nthArg(1), always)]);
这需要一个只与 nextVal 相关的谓词,这似乎是更一般的情况。
问题:
谁能想出一种更实用(无递归)的方式来编写 selfComposeWhile
及其表弟?
R.unfold 主要做你做的,它接受一个种子值(init
),并转换它,并且在每次迭代中它 returns 当前值和新种子价值。在每次迭代中,您需要决定继续或停止使用谓词。
你的函数和 R.unfold 之间的主要区别是最后一个函数产生一个数组,这很容易用 R.last 解决:
const { curry, pipe, unfold, last } = R
const selfComposeWhile = curry(
(pred, fn, init) => pipe(
unfold(n => pred(n, fn(n)) && [n, fn(n)]),
last
)(init)
)
const { ifElse, gt, inc, dec, lt } = R
const incOrDec = ifElse(gt(30), inc, dec)
console.log(selfComposeWhile(lt, incOrDec, 0)) // -> 29
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
我目前确定的解决方案。
我将 selfComposeWhile 命名为 unfoldUntil
。我不确定这是不是最好的名字,因为它 return 不是一个列表。它基本上是 R.until
谓词可以访问上一个和下一个值的地方。
为了使它们更加一致,我将我的 while
行为更改为 until
行为(R.complement
谓词)。
展开直到
如果输入:
unfoldUntil: <T>(
pred: (p:T, n:T) => boolean,
fn: (a:T) => T,
init: T
) => T
已实施
const unfoldUntil = curry(
(pred, fn, init) => pipe(
unfold(n =>
isNil(n) ?
false :
call((next = fn(n)) =>
(pred(n, next) ?
[next, null] :
[next, next])
)
),
last
)(init)
);
注意:这永远不会将null/undefined传递给转换函数(fn
)。您可以使用 return 为空的转换作为停止条件,并 returned 先前的值。否则,您将 returned 使谓词 return 为真的 next
的第一个值。
问题:
我正在学习函数式编程
开个玩笑,还有……
我有一个辅助函数,它一遍又一遍地与自身组合一个函数,直到满足某些条件。就像 f(f(f(f(f(f(f(x)))))))
或 compose(f,f,f,f,f,f,f)(x)
,除了它会一直运行,除非被告知停止。
我实现它的方式,它真的不像合成(而且也许无论如何这里使用的词都是错误的)
这是我目前的解决方案:
const selfComposeWhile = curry(
(pred, fn, init) => {
let prevVal = null;
let nextVal = init;
while(prevVal == null || pred(prevVal, nextVal)){
prevVal = nextVal;
nextVal = fn(nextVal);
}
return nextVal;
}
);
这里正在使用中:
const incOrDec = ifElse(gt(30), inc, dec);
console.log(
selfComposeWhile(lt, incOrDec, 0)
); // -> 29
我不想使用递归,因为 JavaScript 没有正确的尾递归,而且这个网站的同名 (Stack Overflow) 是我如何使用它的真正问题。
没有什么错误,但我一直在尝试通过将它们应用于虚拟问题来学习函数式编程技术,这是我为数不多的几个地方之一代码以绝对必要的方式脱颖而出。
我也有
useWith(selfComposeWhile, [pipe(nthArg(1), always)]);
这需要一个只与 nextVal 相关的谓词,这似乎是更一般的情况。
问题:
谁能想出一种更实用(无递归)的方式来编写 selfComposeWhile
及其表弟?
R.unfold 主要做你做的,它接受一个种子值(init
),并转换它,并且在每次迭代中它 returns 当前值和新种子价值。在每次迭代中,您需要决定继续或停止使用谓词。
你的函数和 R.unfold 之间的主要区别是最后一个函数产生一个数组,这很容易用 R.last 解决:
const { curry, pipe, unfold, last } = R
const selfComposeWhile = curry(
(pred, fn, init) => pipe(
unfold(n => pred(n, fn(n)) && [n, fn(n)]),
last
)(init)
)
const { ifElse, gt, inc, dec, lt } = R
const incOrDec = ifElse(gt(30), inc, dec)
console.log(selfComposeWhile(lt, incOrDec, 0)) // -> 29
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
我目前确定的解决方案。
我将 selfComposeWhile 命名为 unfoldUntil
。我不确定这是不是最好的名字,因为它 return 不是一个列表。它基本上是 R.until
谓词可以访问上一个和下一个值的地方。
为了使它们更加一致,我将我的 while
行为更改为 until
行为(R.complement
谓词)。
展开直到
如果输入:
unfoldUntil: <T>(
pred: (p:T, n:T) => boolean,
fn: (a:T) => T,
init: T
) => T
已实施
const unfoldUntil = curry(
(pred, fn, init) => pipe(
unfold(n =>
isNil(n) ?
false :
call((next = fn(n)) =>
(pred(n, next) ?
[next, null] :
[next, next])
)
),
last
)(init)
);
注意:这永远不会将null/undefined传递给转换函数(fn
)。您可以使用 return 为空的转换作为停止条件,并 returned 先前的值。否则,您将 returned 使谓词 return 为真的 next
的第一个值。