1
+ <!DOCTYPE html>
2
+ < html >
3
+ < head >
4
+ < title > Explicitly Comprehensible FRP</ title >
5
+ < meta charset ="utf-8 ">
6
+ < style >
7
+ @import url (https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
8
+ @import url (https://fonts.googleapis.com/css?family=Droid+Serif:400, 700 , 400italic );
9
+ @import url (https://fonts.googleapis.com/css?family=Ubuntu+Mono:400, 700 , 400italic );
10
+
11
+ body { font-family : 'Droid Serif' ; }
12
+ h1 , h2 , h3 {
13
+ font-family : 'Yanone Kaffeesatz' ;
14
+ font-weight : normal;
15
+ }
16
+ .remark-code , .remark-inline-code { font-family : 'Ubuntu Mono' ; }
17
+ </ style >
18
+ </ head >
19
+ < body >
20
+ < textarea id ="source ">
21
+
22
+ class: center, middle
23
+
24
+ # Explicitly Comprehensible Functional Reactive Programming
25
+
26
+ ## Steve Krouse
27
+
28
+ ---
29
+
30
+ # This talk is about
31
+
32
+ ## 1) the comprehensibility
33
+
34
+ When making a change, it's the first and most-time-consuming step.
35
+
36
+ ## 2) of large
37
+
38
+ Software today is 10k lines minimum but goes up to millions.
39
+
40
+ ## 3) FRP applications.
41
+
42
+ They are becoming increasingly prevalent.
43
+
44
+ ---
45
+
46
+ # This this talk does not have The Answer< sup > TM< sup >
47
+
48
+ I complain about where we are, and point us in a promising direction.
49
+
50
+ ---
51
+
52
+ # FP is comprehensible
53
+ ## 1) Local reasoning
54
+ Code elsewhere cannot affect this code via *side-effects*.
55
+ < br >
56
+ ## 2) Explicit data dependencies
57
+
58
+ We can grok this code by reading its dependency definitions recursively.
59
+
60
+ ---
61
+ # FP is not *always* comprehensible
62
+
63
+ > There is in principle nothing to stop functional programs from **passing a single extra parameter into and out of every single function** in the entire system. If this extra parameter were a **collection (compound value)** of some kind then it could be used to **simulate an arbitrarily large set of mutable variables**...
64
+
65
+ > **...ease of reasoning is lost** (we still know that each function is dependent only upon its arguments, but one of them has become so large and **contains irrelevant values** that the benefit of this knowledge as an aid to understanding is almost nothing). This is however **an extreme example** and does not detract from the general power of the functional approach
66
+
67
+ > -- Out of the Tarpit (Moseley and Marks)
68
+
69
+ ---
70
+
71
+ class: center, middle
72
+
73
+ # This "extreme example" has become the *most popular* pattern in FRP!
74
+
75
+ ---
76
+ class: center, middle
77
+ # The Elm Architecture
78
+
79
+ < iframe width ="300 " height ="300 " src ="https://mermaidjs.github.io/mermaid-live-editor/#/view/eyJjb2RlIjoiXG5ncmFwaCBURFxuIFxudXBkYXRlLS0-IHMyKG5ldyBtb2RlbClcbnMyKG5ldyBtb2RlbCkgLS0-IHZpZXcgXG52aWV3LS0-fG1lc3NhZ2UsIG9sZCBtb2RlbHx1cGRhdGVcbiIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In19 " frameborder ="0 " allowfullscreen =""> </ iframe >
80
+
81
+ ---
82
+
83
+ # Elm Counter
84
+
85
+ < button onclick ="num.innerText -= -1 "> +1</ button > < span id ="num "> 0</ span > < button onclick ="num.innerText -= 1 "> -1</ button >
86
+
87
+ ```
88
+ 01 type alias Model = { count : Int }
89
+ 02
90
+ 03 initialModel : Model
91
+ 04 initialModel = { count = 0 }
92
+ 05
93
+ 06 type Msg = Increment | Decrement
94
+ 07
95
+ 08 update : Msg -> Model -> Model
96
+ 09 update msg model = case msg of
97
+ 10 Increment -> { model | count = model.count + 1 }
98
+ 11 Decrement -> { model | count = model.count - 1 }
99
+ 12
100
+ 13 view : Model -> Html Msg
101
+ 14 view model = div []
102
+ 15 [ button
103
+ 16 [ onClick Increment ]
104
+ 17 [ text "+1" ]
105
+ 18 , span [] [ text < | toString model.count ]
106
+ 19 , button
107
+ 20 [ onClick Decrement ]
108
+ 21 [ text "-1" ]
109
+ 22 ]
110
+ ```
111
+
112
+ ---
113
+
114
+ # Elm Todo MVC
115
+
116
+ < img src ="https://user-images.githubusercontent.com/2288939/43979574-2cef3b36-9cb9-11e8-98f9-7cb25b27326a.png " width ="400px ">
117
+
118
+ ```
119
+ Add ->
120
+ { model
121
+ | uid = model.uid + 1
122
+ , field = ""
123
+ , entries = if String.isEmpty model.field
124
+ then model.entries
125
+ else model.entries ++ [newEntry model.field model.uid ]
126
+ }
127
+ ```
128
+
129
+ ---
130
+
131
+ # Elm TodoMVC diagram
132
+
133
+ <!-- TODO why this and brother blurry? -->
134
+
135
+ < iframe style ="margin-left:-70px " width ="900px " height ="600px " src ="https://mermaidjs.github.io/mermaid-live-editor/#/view/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggdmlld1xudmlld0lucHV0Qm94XG50b2RvQ2hlY2tib3hcbnRvZG9JbnB1dFxuYWN0aXZlQnV0dG9ue2FjdGl2ZUJ1dHRvbn1cbmNvbXBsZXRlZEJ1dHRvbntjb21wbGV0ZWRCdXR0b259XG5hbGxCdXR0b257YWxsQnV0dG9ufVxuZGVsZXRlQnV0dG9uXG5jbGVhckNvbXBsZXRlQnV0dG9uXG5jaGVja0FsbEJveFxuZW5kXG5cbm9sZE1vZGVsLS0-dmlld0lucHV0Qm94XG5vbGRNb2RlbC0tPmNoZWNrQWxsQm94XG5vbGRNb2RlbC0tPnRvZG9DaGVja2JveFxub2xkTW9kZWwtLT50b2RvSW5wdXRcbm9sZE1vZGVsLS0-YWN0aXZlQnV0dG9ue2FjdGl2ZUJ1dHRvbn1cbm9sZE1vZGVsLS0-Y29tcGxldGVkQnV0dG9ue2NvbXBsZXRlZEJ1dHRvbn1cbm9sZE1vZGVsLS0-YWxsQnV0dG9ue2FsbEJ1dHRvbn1cblxudmlld0lucHV0Qm94e0lucHV0Qm94fSAtLT4gQWRkXG52aWV3SW5wdXRCb3h7SW5wdXRCb3h9IC0tPiBVcGRhdGVGaWVsZFxuXG5zdWJncmFwaCBtZXNzYWdlc1xuRGVsZXRlQ29tcGxldGVcbkRlbGV0ZVxuVXBkYXRlRmllbGRcbkFkZFxuQ2hlY2tBbGxcbkNoZWNrXG5FZGl0aW5nRW50cnlcbkNoYW5nZVZpc2liaWxpdHlcblVwZGF0ZUVudHJ5XG5lbmRcblxuICBjaGVja0FsbEJveHtjaGVja0FsbEJveH0gLS0-IENoZWNrQWxsPkNoZWNrQWxsXVxuXG4gICAgdG9kb0NoZWNrYm94e3RvZG9DaGVja2JveH0tLT5DaGVjaz5DaGVja11cbiAgICBkZWxldGVCdXR0b257ZGVsZXRlQnV0dG9ufS0tPkRlbGV0ZT5EZWxldGVdXG4gICAgdG9kb0lucHV0e3RvZG9JbnB1dH0gLS0-IFVwZGF0ZUVudHJ5PlVwZGF0ZUVudHJ5XVxuICAgIHRvZG9JbnB1dCAtLT4gRWRpdGluZ0VudHJ5PkVkaXRpbmdFbnRyeV1cblxuIFxuXG5cblxuQWRkPkFkZF0tLT51cGRhdGVcbkVkaXRpbmdFbnRyeS0tPnVwZGF0ZVxuVXBkYXRlRW50cnktLT51cGRhdGVcbkRlbGV0ZS0tPnVwZGF0ZVxuQ2hlY2stLT51cGRhdGVcbkNoZWNrQWxsLS0-dXBkYXRlXG5VcGRhdGVGaWVsZD5VcGRhdGVGaWVsZF0tLT51cGRhdGVcblxuXG5cbiBjbGVhckNvbXBsZXRlQnV0dG9ue2NsZWFyQ29tcGxldGVCdXR0b259LS0-RGVsZXRlQ29tcGxldGU-RGVsZXRlQ29tcGxldGVdXG5hY3RpdmVCdXR0b257YWN0aXZlQnV0dG9ufS0tPkNoYW5nZVZpc2liaWxpdHk-Q2hhbmdlVmlzaWJpbGl0eV1cbmNvbXBsZXRlZEJ1dHRvbntjb21wbGV0ZWRCdXR0b259LS0-Q2hhbmdlVmlzaWJpbGl0eT5DaGFuZ2VWaXNpYmlsaXR5XVxuYWxsQnV0dG9ue2FsbEJ1dHRvbn0tLT5DaGFuZ2VWaXNpYmlsaXR5PkNoYW5nZVZpc2liaWxpdHldXG5cblxuQ2hhbmdlVmlzaWJpbGl0eS0tPnVwZGF0ZVxuRGVsZXRlQ29tcGxldGUtLT51cGRhdGVcblxub2xkTW9kZWw9PT51cGRhdGVcblxudXBkYXRlLS0-bmV3TW9kZWxcbm9sZE1vZGVsLS4tbmV3TW9kZWxcblxuc3ViZ3JhcGggcmVkdWNlclxudXBkYXRlXG5lbmRcblxuY2xhc3NEZWYgcGluayBmaWxsOnBpbmtcbmNsYXNzIHVwZGF0ZSBwaW5rXG5cbmNsYXNzRGVmIG9yYW5nZSBmaWxsOiNmOTZcbmNsYXNzIG5ld01vZGVsLG9sZE1vZGVsIG9yYW5nZVxuXG5jbGFzc0RlZiBncmVlbiBmaWxsOiM0ZmZmNWFcbmNsYXNzIENoZWNrQWxsLENoZWNrLERlbGV0ZSxVcGRhdGVFbnRyeSxFZGl0aW5nRW50cnksVXBkYXRlRmllbGQsQWRkLERlbGV0ZUNvbXBsZXRlLENoYW5nZVZpc2liaWxpdHkgZ3JlZW4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ " frameborder ="0 " allowfullscreen =""> </ iframe >
136
+
137
+ ---
138
+ # Elm TodoMVC Ctl-F "entries ="
139
+
140
+ < img style ="position: absolute; clip: rect(0px, 300px, 492px, 0px); " src ="https://user-images.githubusercontent.com/2288939/46862901-e237bb00-ce0d-11e8-89ee-fc8a19fb1759.png " height ="700px ">
141
+
142
+ < img style ="position: absolute; top: -350px; right:0px; clip: rect(492px, 300px, 1500px, 0px); " src ="https://user-images.githubusercontent.com/2288939/46862901-e237bb00-ce0d-11e8-89ee-fc8a19fb1759.png " height ="700px ">
143
+
144
+ ---
145
+
146
+ # Elm TodoMVC Ctl-F "entries =" messages
147
+
148
+ < img style ="position: absolute; clip: rect(0px, 300px, 502px, 0px); " src ="https://user-images.githubusercontent.com/2288939/46862900-e237bb00-ce0d-11e8-90d3-5dce86ebc8ff.png " height ="1000px ">
149
+
150
+ < img style ="position: absolute; top: -350px;right:0px; clip: rect(502px, 300px, 1500px, 0px); " src ="https://user-images.githubusercontent.com/2288939/46862900-e237bb00-ce0d-11e8-90d3-5dce86ebc8ff.png " height ="1000px ">
151
+
152
+ ---
153
+
154
+ # Reflex FRP
155
+ haskell, ghcjs
156
+
157
+ ## 1) higher order
158
+
159
+ Stream can contain streams
160
+
161
+ ## 2) cyclic
162
+
163
+ Streams can refer to streams that refer to themselves
164
+
165
+ ---
166
+ # Reflex Counter
167
+
168
+ ```
169
+ 01 button :: Text -> m (Event ())
170
+ 02 el :: Text -> m a -> m a
171
+ 03 display :: Show a => Dynamic a -> m ()
172
+ 04 (< $) :: a -> Event b -> Event a
173
+ 05 leftmost :: [Event a] -> Event a
174
+ 06 foldDyn :: (a -> b -> b) -> b -> Event a -> m (Dynamic b)
175
+ 09
176
+ 08 bodyElement :: MonadWidget t m => m ()
177
+ 09 bodyElement = do
178
+ 10 rec evIncr < - button "+1"
179
+ 11 el "div" $ display count
180
+ 12 evDecr < - button "-1"
181
+ 13 count < - foldDyn (+) 0 $ leftmost
182
+ 14 [ 1 < $ evIncr
183
+ 15 , -1 < $ evDecr
184
+ 16 ]
185
+ 17 return ()
186
+ 18
187
+ 19 main :: IO ()
188
+ 20 main = mainWidget bodyElement
189
+ ```
190
+
191
+
192
+ ---
193
+ # Reflex TodoMVC Entries
194
+
195
+ ```
196
+ 01 initialTasks :: Map Int Task
197
+ 02 initialTasks = Map.empty
198
+ 03
199
+ 04 insertNew_ :: Task - > Map Int Task -> Map Int Task
200
+ 05
201
+ 06 todoMVC :: (DomBuilder t m, MonadFix m, MonadHold t m) => m ()
202
+ 07 todoMVC = do
203
+ 08 el "div" $ do
204
+ 09 elAttr "section" ("class" =: "todoapp") $ do
205
+ 10 mainHeader
206
+ 11 rec tasks < - foldDyn ($) initialTasks $
207
+ 12 mergeWith (.)
208
+ 13 [ fmap insertNew_ newTask
209
+ 14 , listModifyTasks
210
+ 15 , fmap (const $ Map.filter $ not . taskCompleted) clearCompleted
211
+ 16 ]
212
+ 17 newTask < - taskEntry
213
+ 18 listModifyTasks < - taskList activeFilter tasks
214
+ 19 (activeFilter, clearCompleted) < - controls tasks
215
+ 20 return ()
216
+ 21 infoFooter
217
+ ```
218
+
219
+ Cycle: `tasks` depends upon `listModifyTasks` and `clearCompleted`, which depend upon `tasks`
220
+
221
+ ---
222
+ # Reflex TodoMVC Diagram
223
+
224
+ < iframe style ="margin-left:-50px " width ="900px " height ="500px " overflow ="scroll " frameborder ="none " src ="https://mermaidjs.github.io/mermaid-live-editor/#/view/eyJjb2RlIjoiZ3JhcGggVERcblxubmV3VGFza0V2ZW50Pm5ld1Rhc2tFdmVudF09PT4gdGFza3Ncbmxpc3RNb2RpZnlUYXNrcz5saXN0TW9kaWZ5VGFza3NdID09PiB0YXNrc1xuXG5jbGVhckNvbXBsZXRlZEV2ZW50PmNsZWFyQ29tcGxldGVkRXZlbnRdID09PiB0YXNrc1xudGFza3MgLS0-IHZpc2libGVUYXNrc1xuXG5hY3RpdmVGaWx0ZXItLT52aXNpYmxlVGFza3NcbnN1YmdyYXBoIHRhc2tMaXN0XG4gICAgdmlzaWJsZVRhc2tzLS0-Y29tcGxldGVkQ2hlY2tib3h7Y29tcGxldGVkQ2hlY2tib3h9XG4gICAgdmlzaWJsZVRhc2tzLS0-IGRlc2NyaXB0aW9uTGFiZWx7ZGVzY3JpcHRpb25MYWJlbH1cbiAgICB2aXNpYmxlVGFza3MtLT4gZWRpdEJveHtlZGl0Qm94fVxuICAgICB0b2dnbGVBbGxDaGVja2JveHt0b2dnbGVBbGxDaGVja2JveH0tLT50b2dnbGVBbGw-dG9nZ2xlQWxsXVxuICAgIHRvZ2dsZUFsbC0tPmxpc3RNb2RpZnlUYXNrc1xuICAgIHRvZ2dsZUFsbC0tPnRvZ2dsZVN0YXRlXG4gICB0b2dnbGVTdGF0ZS0tPnRvZ2dsZUFsbENoZWNrYm94XG4gICAgY2hhbmdlU2VsZj5jaGFuZ2VTZWxmXS0tPml0ZW1DaGFuZ2VzPml0ZW1DaGFuZ2VzXVxuICAgIGl0ZW1DaGFuZ2VzPml0ZW1DaGFuZ2VzXS0tPmxpc3RNb2RpZnlUYXNrc1xuICAgICBzdWJncmFwaCB0b2RvSXRlbVxuICAgICAgICAgIGVkaXRCb3h7ZWRpdEJveH0tLT5lZGl0Qm94RW50ZXI-ZWRpdEJveEVudGVyXVxuICAgICAgICAgIGVkaXRCb3gtLT5lZGl0Qm94VGV4dFZhbHVlXG4gICAgICAgICAgZWRpdEJveFRleHRWYWx1ZS0tPnNldERlc2NyaXB0aW9uPnNldERlc2NyaXB0aW9uXVxuICAgICAgICAgIGVkaXRCb3hFbnRlci0tPnNldERlc2NyaXB0aW9uPnNldERlc2NyaXB0aW9uXVxuICAgICAgICAgIGVkaXRCb3gtLT58b24gZXNjIGtleXxjYW5jZWxFZGl0XG4gICAgICAgICAgZGVzdHJveUJ1dHRvbntkZXN0cm95QnV0dG9ufS0tPmRlc3Ryb3lcbiAgICAgICAgICBkZXNjcmlwdGlvbkxhYmVse2Rlc2NyaXB0aW9uTGFiZWx9LS0-fG9uIGRvdWJsZSBjbGlja3xzdGFydEVkaXRpbmdcbiAgICAgICAgICBjb21wbGV0ZWRDaGVja2JveHtjb21wbGV0ZWRDaGVja2JveH0tLT5zZXRDb21wbGV0ZWRcbiAgICAgICAgICBlZGl0Qm94RW50ZXItLT5lZGl0aW5nXG4gICAgICAgICAgc3RhcnRFZGl0aW5nPnN0YXJ0RWRpdGluZ10tLT5lZGl0aW5nXG4gICAgICAgICAgY2FuY2VsRWRpdD5jYW5jZWxFZGl0XS0tPmVkaXRpbmdcbiAgICAgICAgICBzZXRDb21wbGV0ZWQ-c2V0Q29tcGxldGVkXS0tPmNoYW5nZVNlbGZcbiAgICAgICAgICBkZXN0cm95PmRlc3Ryb3ldLS0-Y2hhbmdlU2VsZlxuICAgICAgICAgIHNldERlc2NyaXB0aW9uPnNldERlc2NyaXB0aW9uXSAtLT5jaGFuZ2VTZWxmXG4gICAgICAgICAgZWRpdGluZy0tPnxoaWRlcy9zaG93cyB2aWEgY3NzfGVkaXRCb3hcbiAgICAgICAgICBlZGl0aW5nLS0-fGhpZGVzL3Nob3dzIHZpYSBjc3N8ZGVzY3JpcHRpb25MYWJlbFxuICAgICBlbmRcbmVuZFxuXG5zdWJncmFwaCBjb250cm9sc1xuICAgIGFsbEJ1dHRvbnthbGxCdXR0b259IC0tPmFsbEJ1dHRvbkNsaWNrZWQ-YWxsQnV0dG9uQ2xpY2tlZF1cbiAgICBhY3RpdmVCdXR0b257YWN0aXZlQnV0dG9ufS0tPmFjdGl2ZUJ1dHRvbkNsaWNrZWQ-YWN0aXZlQnV0dG9ubkNsaWNrZWRdXG4gICAgY29tcGxldGVkQnV0dG9ue2NvbXBsZXRlZEJ1dHRvbn0gLS0-Y29tcGxldGVkQnV0dG9uQ2xpY2tlZD5jb21wbGV0ZWRCdXR0b25DbGlja2VkXVxuICAgYWxsQnV0dG9uQ2xpY2tlZFxuICAgIGFsbEJ1dHRvbkNsaWNrZWQtLT5hY3RpdmVGaWx0ZXJcbiAgICBhY3RpdmVCdXR0b25DbGlja2VkLS0-YWN0aXZlRmlsdGVyXG4gICAgY29tcGxldGVkQnV0dG9uQ2xpY2tlZC0tPmFjdGl2ZUZpbHRlclxuICAgIGFjdGl2ZUZpbHRlci0tPmFjdGl2ZUJ1dHRvblxuICAgIGFjdGl2ZUZpbHRlci0tPmNvbXBsZXRlZEJ1dHRvblxuICAgIGFjdGl2ZUZpbHRlci0tPmFsbEJ1dHRvblxuICAgIGNsZWFyQ29tcGxldGVkQnV0dG9ue2NsZWFyQ29tcGxldGVkQnV0dG9ufS0tPmNsZWFyQ29tcGxldGVkRXZlbnRcbiAgICBhY3RpdmVGaWx0ZXItLT50b2RvUmVtYWluaW5nQ291bnRcbmVuZFxuXG5zdWJncmFwaCB0YXNrRW50cnlcbiAgIGRlc2NyaXB0aW9uQm94e2Rlc2NyaXB0aW9uQm94fS0tPlxuZGVzY3JpcHRpb25Cb3hFbnRlcj5kZXNjcmlwdGlvbkJveEVudGVyXVxuICBkZXNjcmlwdGlvbkJveHtkZXNjcmlwdGlvbkJveH0tLT5cbmRlc2NyaXB0aW9uQm94VmFsdWVcbiAgZGVzY3JpcHRpb25Cb3hFbnRlci0tPm5ld1Rhc2tFdmVudFxuICBkZXNjcmlwdGlvbkJveFZhbHVlLS0-bmV3VGFza0V2ZW50XG4gIGRlc2NyaXB0aW9uQm94RW50ZXItLT58Y2xlYXIgb24gZW50ZXJ8ZGVzY3JpcHRpb25Cb3h7ZGVzY3JpcHRpb25Cb3h9XG5lbmRcblxudGFza3MgLS0-IHRvZG9SZW1haW5pbmdDb3VudFxuXG5jbGFzc0RlZiBvcmFuZ2UgZmlsbDojZjk2XG5jbGFzcyB0YXNrcyxhY3RpdmVGaWx0ZXIsdG9kb1JlbWFpbmluZ0NvdW50LHZpc2libGVUYXNrcyxlZGl0aW5nLGl0ZW1zLHRvZ2dsZVN0YXRlLGVkaXRCb3hUZXh0VmFsdWUsZGVzY3JpcHRpb25Cb3hWYWx1ZSBvcmFuZ2VcblxuY2xhc3NEZWYgZ3JlZW4gZmlsbDojNGZmZjVhXG5jbGFzcyBuZXdUYXNrRXZlbnQsY2xlYXJDb21wbGV0ZWRFdmVudCxzZXRDb21wbGV0ZWQsZGVzdHJveSxjaGFuZ2VTZWxmLHNldERlc2NyaXB0aW9uLHN0YXJ0RWRpdGluZyxjYW5jZWxFZGl0LHRvZ2dsZUFsbCxsaXN0TW9kaWZ5VGFza3MsYWxsQnV0dG9uQ2xpY2tlZCxhY3RpdmVCdXR0b25DbGlja2VkLGNvbXBsZXRlZEJ1dHRvbkNsaWNrZWQsZGVzY3JpcHRpb25Cb3hFbnRlcixpdGVtQ2hhbmdlcyxlZGl0Qm94RW50ZXIgZ3JlZW4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ "> </ iframe >
225
+
226
+ ---
227
+ # Reflex TodoMVC Diagram (Simplified)
228
+
229
+ < iframe style ="margin-left:-50px " width ="620px " height ="500px " overflow ="scroll " frameborder ="none " src ="./reflex-diagram-simplified.svg "> </ iframe >
230
+
231
+ ---
232
+
233
+ # Is the cure worse than the disease?
234
+
235
+ ### - Serializeable Elm singleton -> time travel debugging, hot reloading
236
+ ### - Reflex + ghcjs is annoying
237
+
238
+ ---
239
+ # Conclusion
240
+
241
+ ## I hope you are now _unhappy_ with where we are. And excited to look for other solutions. Such a _higher-order_ and _cyclic_ streams. So that we can... (please forgive me)
242
+
243
+
244
+ </ textarea >
245
+ < script src ="https://remarkjs.com/downloads/remark-latest.min.js ">
246
+ </ script >
247
+ < script >
248
+ var slideshow = remark . create ( { highlightLanguage : 'haskell' } ) ;
249
+ slideshow . gotoSlide ( 16 ) ;
250
+ </ script >
251
+ </ body>
252
+ </ html>
0 commit comments