|
| 1 | +module MemoizeFibonacci.Main where |
| 2 | + |
| 3 | +import Prelude |
| 4 | +import Data.Function.Memoize (memoize) |
| 5 | +import Data.Interpolate (i) |
| 6 | +import Debug.Trace (spy) |
| 7 | +import Effect (Effect) |
| 8 | +import Effect.Class.Console (log) |
| 9 | + |
| 10 | +main :: Effect Unit |
| 11 | +main = do |
| 12 | + log $ i "basic fib result: " $ fib 7 |
| 13 | + log $ i "fibFast result: " $ fibFast 7 |
| 14 | + log $ i "fibSlow result: " $ fibSlow 7 |
| 15 | + |
| 16 | + -- The following variations type-check, but do not correctly memoize |
| 17 | + -- the functions. They are commented out intentionally. Uncomment them |
| 18 | + -- and run them to see for yourself. |
| 19 | + -- log $ i "fibBroken1 result: " $ fibBroken1 7 |
| 20 | + -- log $ i "fibBroken2 result: " $ fibBroken2 7 |
| 21 | + -- log $ i "fibBroken3 result: " $ fibBroken3 7 |
| 22 | + |
| 23 | + -- Note: this one fails to compile. |
| 24 | + -- log $ i "fibBroken4 result: " $ fibBroken4 7 |
| 25 | + |
| 26 | +-- Basic fibonacci implementation |
| 27 | +fib :: Int -> Int |
| 28 | +fib 0 = 0 |
| 29 | +fib 1 = 1 |
| 30 | +fib n = fib (n - 2) + fib (n - 1) |
| 31 | + |
| 32 | +-------------------------------------------------------------------------- |
| 33 | + |
| 34 | +-- Same as `fib`, but with `spy` statements added to reveal duplicated work |
| 35 | +fibSlow :: Int -> Int |
| 36 | +fibSlow 0 = spy "fibSlow 0" 0 |
| 37 | +fibSlow 1 = spy "fibSlow 1" 1 |
| 38 | +fibSlow n = |
| 39 | + spy ("fibSlow " <> show n) |
| 40 | + $ fibSlow (n - 2) |
| 41 | + + fibSlow (n - 1) |
| 42 | + |
| 43 | +-------------------------------------------------------------------------- |
| 44 | + |
| 45 | +-- Fast memoized version of fibonacci |
| 46 | +fibFast :: Int -> Int |
| 47 | +fibFast 0 = spy "fibFast 0" 0 |
| 48 | +fibFast 1 = spy "fibFast 1" 1 |
| 49 | +fibFast n = |
| 50 | + spy ("fibFast " <> show n) |
| 51 | + $ fibMemo (n - 2) |
| 52 | + + fibMemo (n - 1) |
| 53 | + |
| 54 | +fibMemo :: Int -> Int |
| 55 | +fibMemo = memoize \n -> fibFast n |
| 56 | + |
| 57 | +-------------------------------------------------------------------------- |
| 58 | +-------------------------------------------------------------------------- |
| 59 | + |
| 60 | +-- Broken due to the `memoize` function being written in a non-thunked form |
| 61 | +fibBroken1 :: Int -> Int |
| 62 | +fibBroken1 0 = spy "fibBroken1 0" 0 |
| 63 | +fibBroken1 1 = spy "fibBroken1 1" 1 |
| 64 | +fibBroken1 n = |
| 65 | + spy ("fibBroken1 " <> show n) |
| 66 | + $ fibNonThunkedMemoize (n - 2) |
| 67 | + + fibNonThunkedMemoize (n - 1) |
| 68 | + |
| 69 | +fibNonThunkedMemoize :: Int -> Int |
| 70 | +fibNonThunkedMemoize n = memoize fibBroken1 n |
| 71 | + |
| 72 | +-------------------------------------------------------------------------- |
| 73 | + |
| 74 | +-- Broken due to using a let clause within the function body to define |
| 75 | +-- memoized function rather than memoizing function outside of its body |
| 76 | +fibBroken2 :: Int -> Int |
| 77 | +fibBroken2 0 = spy "fibBroken2 0" 0 |
| 78 | +fibBroken2 1 = spy "fibBroken2 1" 1 |
| 79 | +fibBroken2 n = |
| 80 | + let |
| 81 | + fibLetClauseMemoize = memoize \n -> fibBroken2 n |
| 82 | + in spy ("fibBroken2 " <> show n) |
| 83 | + $ fibLetClauseMemoize (n - 2) |
| 84 | + + fibLetClauseMemoize (n - 1) |
| 85 | + |
| 86 | +-------------------------------------------------------------------------- |
| 87 | + |
| 88 | +-- Broken due to using a where clause within the function body to define |
| 89 | +-- memoized function rather than memoizing function outside of its body |
| 90 | +fibBroken3 :: Int -> Int |
| 91 | +fibBroken3 0 = spy "fibBroken3 0" 0 |
| 92 | +fibBroken3 1 = spy "fibBroken3 1" 1 |
| 93 | +fibBroken3 n = |
| 94 | + spy ("fibBroken3 " <> show n) |
| 95 | + $ fibWhereClauseMemoize (n - 2) |
| 96 | + + fibWhereClauseMemoize (n - 1) |
| 97 | + where |
| 98 | + fibWhereClauseMemoize = memoize \n -> fibBroken3 n |
| 99 | + |
| 100 | +-------------------------------------------------------------------------- |
| 101 | + |
| 102 | +-- Note: This version fails to compile completely. |
| 103 | + |
| 104 | +-- Broken due to the `memoize` function being written in a point-free form |
| 105 | +-- fibBroken4 :: Int -> Int |
| 106 | +-- fibBroken4 0 = spy "fibBroken4 0" 0 |
| 107 | +-- fibBroken4 1 = spy "fibBroken4 1" 1 |
| 108 | +-- fibBroken4 n = |
| 109 | +-- spy ("fibBroken4 " <> show n) |
| 110 | +-- $ fibPointFreeMemoize (n - 2) |
| 111 | +-- + fibPointFreeMemoize (n - 1) |
| 112 | +-- |
| 113 | +-- fibPointFreeMemoize :: Int -> Int |
| 114 | +-- fibPointFreeMemoize = memoize fibBroken4 |
0 commit comments