/
07_factorial_tailRecM.worksheet.sc
45 lines (38 loc) · 1.39 KB
/
07_factorial_tailRecM.worksheet.sc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//Demonstration of stack-safe factorial implementation.
//FlatMap[F].tailRecM and explicit state class are used.
import cats.implicits.catsSyntaxEitherId
import cats.{ FlatMap, Id }
/** @param current
* value that fixes
* @param accumulator
*/
case class FactorialStepState(current: Int, accumulator: BigInt) {
/** Generates state for next iteration (in terms of algorithm that decreases a value on each step)
* @return
* updated state
*/
def multiplyAndDecrement: FactorialStepState =
this.copy(current = this.current - 1, accumulator = this.current * this.accumulator)
}
object FactorialStepState {
val initial: Int => FactorialStepState = x => FactorialStepState(x, 1)
}
def factorial0(x: Int): BigInt =
FlatMap[Id].tailRecM[FactorialStepState, BigInt](FactorialStepState.initial(x))(state =>
if (state.current == 0) state.accumulator.asRight
else
FactorialStepState(
current = state.current - 1,
accumulator = state.current * state.accumulator
).asLeft
)
/** @param x
* @see <a href="https://typelevel.org/cats/api/cats/FlatMap.html">cats/FlatMap</a>
* @return
*/
def factorial(x: Int): BigInt =
FlatMap[Id].tailRecM[FactorialStepState, BigInt](FactorialStepState.initial(x))(state =>
if (state.current == 0) state.accumulator.asRight else state.multiplyAndDecrement.asLeft
)
val result = factorial(20000)
println(result)