SHOW:
|
|
- or go back to the newest paste.
| 1 | ||
| 2 | - | /** |
| 2 | + | // Not a super great example, but here is `fib` using state-threading. You can |
| 3 | - | * Not a super great example, but here is `fib` using state-threading. You can |
| 3 | + | // use this same technique for `pascal` or any function you'd like to memoize. |
| 4 | - | * use this same technique for `pascal` or any function you'd like to memoize. |
| 4 | + | // If you continue with FP you will learn how to do this with the State monad, |
| 5 | - | * If you continue with FP you will learn how to do this with the State monad, |
| 5 | + | // (which removes most of the clutter) and the Free monad (which allows you to |
| 6 | - | * (which removes most of the clutter) and the Free monad (which allows you to |
| 6 | + | // use general recursion without consuming stack). |
| 7 | - | * use general recursion without consuming stack). |
| 7 | + | |
| 8 | - | */ |
| 8 | + | |
| 9 | // Calculate the nth Fibonacci number using a recursive algorithm. Note that | |
| 10 | // this will run out of stack space for large values of `n` (around 6000 for | |
| 11 | - | /** |
| 11 | + | // me, but it will depend on VM settings. |
| 12 | - | * Calculate the nth Fibonacci number using a recursive algorithm. Note that |
| 12 | + | |
| 13 | - | * this will run out of stack space for large values of `n` (around 6000 for |
| 13 | + | |
| 14 | - | * me, but it will depend on VM settings. |
| 14 | + | |
| 15 | - | */ |
| 15 | + | |
| 16 | ||
| 17 | // The actual implementation threads our state, so it consumes an initial | |
| 18 | // memo and returns the answer along with a [possibly new] memo. | |
| 19 | def fib0(n: Int, m: Memo): (Memo, BigInt) = | |
| 20 | if (n < 3) (m, BigInt(1)) // Our base case | |
| 21 | else m.get(n) match {
| |
| 22 | case Some(a) => (m, a) // Answer is already known | |
| 23 | case None => // Need to calculate | |
| 24 | val (mx, a) = {
| |
| 25 | val (m0, a0) = fib0(n - 2, m) // Note the data flow from here | |
| 26 | val (m1, a1) = fib0(n - 1, m0) // ... to here | |
| 27 | (m1, a0 + a1) // ... to here | |
| 28 | } | |
| 29 | (mx + (n -> a), a) // A new memo, and our answer | |
| 30 | } | |
| 31 | ||
| 32 | // Delegate to `fib0` with an initial empty memo, and then throw the memo | |
| 33 | // away when we get our answer back. We could also return the memo as part | |
| 34 | // of the public API so it could be used again later; here we rebuild it | |
| 35 | // each time someone calls the top-level `fib`. | |
| 36 | require(n > 0, "fib(n) is defined only for positive n") | |
| 37 | fib0(n, Map())._2 | |
| 38 | ||
| 39 | } | |
| 40 | ||
| 41 | // Calculate a rather large number, then print it out in chunks. | |
| 42 | val big = fib(2500) | |
| 43 | println(big.toString.grouped(80).mkString("\n"))
| |
| 44 | ||
| 45 | } |