Skip to content

Commit 5f1eacb

Browse files
Memoize fibonacci (#187)
* Add MemoizeFibonacci * Remove Purty newlines * Undo purty squish * Move main function to top of file * Add example: which variations will break memoize function; ignore broken4 fibBroken4 fails to compile. Not sure whether this is a compiler bug or not. Co-authored-by: Jordan Martinez <[email protected]>
1 parent 62864be commit 5f1eacb

File tree

8 files changed

+221
-0
lines changed

8 files changed

+221
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ Running a web-compatible recipe:
122122
| | :heavy_check_mark: | [InterpretHalogenHooks](recipes/InterpretHalogenHooks) | Demonstrates how to use a custom monad (in this case, using `ReaderT` with `Aff` as the effect type) for a component, and then interpreting that custom monad back down to `Aff`, so it can be run as a normal component. |
123123
| | :heavy_check_mark: | [KeyboardInputHalogenHooks](recipes/KeyboardInputHalogenHooks) | This example demonstrates how to selectively capture keyboard events and, more generally, how to use `EventSource`s in Halogen. |
124124
| | :heavy_check_mark: | [LifecycleHalogenHooks](recipes/LifecycleHalogenHooks) | Demonstrates component lifecycle. |
125+
| :heavy_check_mark: | :heavy_check_mark: | [MemoizeFibonacci](recipes/MemoizeFibonacci) | This recipe demonstrates correct and incorrect use of the [`memoize`](https://pursuit.purescript.org/packages/purescript-memoize/docs/Data.Function.Memoize#v:memoize) function by calculating the fibonacci sequence. |
125126
| | :heavy_check_mark: | [NumbersHalogenHooks](recipes/NumbersHalogenHooks) | A Halogen port of the ["Random - Numbers" Elm Example](https://elm-lang.org/examples/numbers). |
126127
| | :heavy_check_mark: | [NumbersReactHooks](recipes/NumbersReactHooks) | A React port of the ["Random - Numbers" Elm Example](https://elm-lang.org/examples/numbers). |
127128
| | :heavy_check_mark: | [PositionsHalogenHooks](recipes/PositionsHalogenHooks) | A Halogen port of the ["Random - Positions" Elm Example](https://elm-lang.org/examples/positions). |

recipes/MemoizeFibonacci/.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/bower_components/
2+
/node_modules/
3+
/.pulp-cache/
4+
/output/
5+
/generated-docs/
6+
/.psc-package/
7+
/.psc*
8+
/.purs*
9+
/.psa*
10+
/.spago
11+
/web-dist/
12+
/prod-dist/
13+
/prod/

recipes/MemoizeFibonacci/README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# MemoizeFibonacci
2+
3+
This recipe demonstrates correct and incorrect use of the [`memoize`](https://pursuit.purescript.org/packages/purescript-memoize/docs/Data.Function.Memoize#v:memoize) function by calculating the fibonacci sequence.
4+
5+
## Expected Behavior:
6+
7+
### Node.js
8+
9+
Prints the following to console, which demonstrates `fibFast` is memoized correctly, while `fibSlow` is not.
10+
11+
```
12+
basic fib result: 13
13+
fibFast 1: 1
14+
fibFast 0: 0
15+
fibFast 2: 1
16+
fibFast 3: 2
17+
fibFast 4: 3
18+
fibFast 5: 5
19+
fibFast 6: 8
20+
fibFast 7: 13
21+
fibFast result: 13
22+
fibSlow 1: 1
23+
fibSlow 0: 0
24+
fibSlow 1: 1
25+
fibSlow 2: 1
26+
fibSlow 3: 2
27+
fibSlow 0: 0
28+
fibSlow 1: 1
29+
fibSlow 2: 1
30+
fibSlow 1: 1
31+
fibSlow 0: 0
32+
fibSlow 1: 1
33+
fibSlow 2: 1
34+
fibSlow 3: 2
35+
fibSlow 4: 3
36+
fibSlow 5: 5
37+
fibSlow 0: 0
38+
fibSlow 1: 1
39+
fibSlow 2: 1
40+
fibSlow 1: 1
41+
fibSlow 0: 0
42+
fibSlow 1: 1
43+
fibSlow 2: 1
44+
fibSlow 3: 2
45+
fibSlow 4: 3
46+
fibSlow 1: 1
47+
fibSlow 0: 0
48+
fibSlow 1: 1
49+
fibSlow 2: 1
50+
fibSlow 3: 2
51+
fibSlow 0: 0
52+
fibSlow 1: 1
53+
fibSlow 2: 1
54+
fibSlow 1: 1
55+
fibSlow 0: 0
56+
fibSlow 1: 1
57+
fibSlow 2: 1
58+
fibSlow 3: 2
59+
fibSlow 4: 3
60+
fibSlow 5: 5
61+
fibSlow 6: 8
62+
fibSlow 7: 13
63+
fibSlow result: 13
64+
```
65+
66+
### Browser
67+
68+
Prints same output as above to dev console when the page is loaded.
69+
70+
Make sure to open the console with dev tools first, then reload/refresh the page.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This file just indicates that the node backend is supported.
2+
It is used for CI and autogeneration purposes.

recipes/MemoizeFibonacci/spago.dhall

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{ name = "MemoizeFibonacci"
2+
, dependencies =
3+
[ "console", "debug", "effect", "interpolate", "memoize", "psci-support" ]
4+
, packages = ../../packages.dhall
5+
, sources = [ "recipes/MemoizeFibonacci/src/**/*.purs" ]
6+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<title>MemoizeFibonacci</title>
7+
</head>
8+
9+
<body>
10+
<script src="./index.js"></script>
11+
</body>
12+
13+
</html>

recipes/MemoizeFibonacci/web/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"use strict";
2+
require("../../../output/MemoizeFibonacci.Main/index.js").main();

0 commit comments

Comments
 (0)