@@ -25,140 +25,179 @@ import Effect.Class (class MonadEffect)
25
25
import Effect.Console (log )
26
26
import Effect.Exception (Error )
27
27
28
- type WidgetStepRecord v a =
29
- { view :: v
30
- , cont :: Aff a
31
- }
28
+ type WidgetStepRecord v a
29
+ = { view :: v , cont :: Aff a }
32
30
33
- newtype WidgetStep v a = WidgetStep (Effect (Either a (WidgetStepRecord v a )))
31
+ newtype WidgetStep v a
32
+ = WidgetStep (Effect (Either a (WidgetStepRecord v a )))
34
33
35
- unWidgetStep :: forall v a . WidgetStep v a -> Effect (Either a (WidgetStepRecord v a ))
34
+ unWidgetStep ::
35
+ forall v a .
36
+ WidgetStep v a ->
37
+ Effect (Either a (WidgetStepRecord v a ))
36
38
unWidgetStep (WidgetStep x) = x
37
39
38
40
-- derive instance widgetStepFunctor :: Functor (WidgetStep v)
39
-
40
41
instance functorWidgetStep :: Functor (WidgetStep v ) where
41
42
map f (WidgetStep w) = WidgetStep (map mod w)
42
- where mod (Right ws) = Right (ws { cont = map f ws.cont })
43
- mod (Left a) = Left (f a)
43
+ where
44
+ mod (Right ws) = Right (ws { cont = map f ws.cont
45
+ })
46
+ mod (Left a) = Left (f a)
44
47
45
48
displayStep :: forall a v . v -> WidgetStep v a
46
49
displayStep v = WidgetStep (pure (Right { view: v, cont: never }))
47
50
48
- newtype Widget v a = Widget (Free (WidgetStep v ) a )
51
+ newtype Widget v a
52
+ = Widget (Free (WidgetStep v ) a )
53
+
49
54
unWidget :: forall v a . Widget v a -> Free (WidgetStep v ) a
50
55
unWidget (Widget w) = w
51
56
52
57
derive newtype instance widgetFunctor :: Functor (Widget v )
58
+
53
59
derive newtype instance widgetBind :: Bind (Widget v )
60
+
54
61
derive newtype instance widgetApplicative :: Applicative (Widget v )
62
+
55
63
derive newtype instance widgetApply :: Apply (Widget v )
64
+
56
65
instance widgetMonad :: Monad (Widget v )
66
+
57
67
derive newtype instance widgetMonadRec :: MonadRec (Widget v )
58
68
59
69
instance widgetShiftMap :: ShiftMap (Widget v ) (Widget v ) where
60
70
shiftMap = identity
61
71
62
72
-- Util
63
- flipEither :: forall a b . Either a b -> Either b a
73
+ flipEither ::
74
+ forall a b .
75
+ Either a b ->
76
+ Either b a
64
77
flipEither (Left a) = Right a
78
+
65
79
flipEither (Right b) = Left b
66
80
67
81
resume :: forall f a . Functor f => Free f a -> Either a (f (Free f a ))
68
- resume = resume' (\g i -> Right (i <$> g)) Left
82
+ resume = resume' (\g i ->
83
+ Right (i <$> g)) Left
69
84
70
- instance widgetMultiAlternative :: Monoid v => MultiAlternative (Widget v ) where
85
+ instance widgetMultiAlternative ::
86
+ ( Monoid v
87
+ ) =>
88
+ MultiAlternative (Widget v ) where
71
89
orr wss = case fromArray wss of
72
90
Just wsne -> Widget $ comb $ map unWidget wsne
73
91
Nothing -> empty
74
92
where
75
- comb :: forall v' a . Monoid v'
76
- => NonEmptyArray (Free (WidgetStep v' ) a )
77
- -> Free (WidgetStep v' ) a
78
- -- If any sub-widget finished, then finish
79
- -- 'Either.traverse'
80
- comb wfs = case traverse resume wfs of
81
- Left a -> pure a
82
- Right wsm -> wrap $ WidgetStep do
83
- -- 'Effect.traverse'
84
- ewss <- traverse unWidgetStep wsm
85
- -- 'Effect.traverse'
86
- ws <- traverse stepWidget ewss
87
- pure (Right
88
- { view: foldMap1 _.view ws
89
- , cont: merge ws (map _.cont ws)
90
- })
91
-
92
- stepWidget :: forall v' a . Monoid v'
93
- => Either (Free (WidgetStep v' ) a ) (WidgetStepRecord v' (Free (WidgetStep v' ) a ))
94
- -> Effect (WidgetStepRecord v' (Free (WidgetStep v' ) a ))
95
- stepWidget (Left w) = case resume w of
96
- Left a -> pure {view: mempty, cont: pure (pure a)}
97
- Right (WidgetStep effws) -> do
98
- ews <- effws
99
- case ews of
100
- Left w' -> stepWidget (Left w')
101
- Right ws -> pure ws
102
- stepWidget (Right ws) = pure ws
103
-
104
- merge :: forall v' a . Monoid v'
105
- => NonEmptyArray (WidgetStepRecord v' (Free (WidgetStep v' ) a ))
106
- -> NonEmptyArray (Aff (Free (WidgetStep v' ) a ))
107
- -> Aff (Free (WidgetStep v' ) a )
108
- merge ws wscs = do
109
- -- wsm' is discharged wsm, with all the Aff action run exactly once
110
- let wsm = map (wrap <<< WidgetStep <<< pure <<< Right ) ws
111
- -- TODO: We know the array is non-empty. We need something like foldl1WithIndex.
112
- Tuple i e <- sequential (foldlWithIndex (\i r w -> alt (parallel (map (Tuple i) w)) r) empty wscs)
113
- -- TODO: All the Aff in ws is already discharged. Use a more efficient way than comb to process it
114
- -- TODO: Also, more importantly, we would like to not have to cancel running fibers unless one of them returns a result
115
- pure $ comb (fromMaybe wsm (updateAt i e wsm))
116
-
117
- instance widgetSemigroup :: Monoid v => Semigroup (Widget v a ) where
93
+ comb ::
94
+ forall v' a .
95
+ Monoid v' =>
96
+ NonEmptyArray (Free (WidgetStep v' ) a ) ->
97
+ Free (WidgetStep v' ) a
98
+ -- If any sub-widget finished, then finish
99
+ -- 'Either.traverse'
100
+ comb wfs = case traverse resume wfs of
101
+ Left a -> pure a
102
+ Right wsm -> wrap $ WidgetStep do
103
+ -- 'Effect.traverse'
104
+ ewss <- traverse unWidgetStep wsm
105
+ -- 'Effect.traverse'
106
+ ws <- traverse stepWidget ewss
107
+ pure (Right { view: foldMap1 _.view ws
108
+ , cont: merge ws (map _.cont ws)
109
+ })
110
+ stepWidget ::
111
+ forall v' a .
112
+ Monoid v' =>
113
+ Either (Free (WidgetStep v' ) a ) (WidgetStepRecord v' (Free (WidgetStep v' ) a )) ->
114
+ Effect (WidgetStepRecord v' (Free (WidgetStep v' ) a ))
115
+ stepWidget (Left w) = case resume w of
116
+ Left a -> pure { view: mempty
117
+ , cont: pure (pure a)
118
+ }
119
+ Right (WidgetStep effws) -> do
120
+ ews <- effws
121
+ case ews of
122
+ Left w' -> stepWidget (Left w')
123
+ Right ws -> pure ws
124
+ stepWidget (Right ws) = pure ws
125
+ merge ::
126
+ forall v' a .
127
+ Monoid v' =>
128
+ NonEmptyArray (WidgetStepRecord v' (Free (WidgetStep v' ) a )) ->
129
+ NonEmptyArray (Aff (Free (WidgetStep v' ) a )) ->
130
+ Aff (Free (WidgetStep v' ) a )
131
+ merge ws wscs = do
132
+ -- wsm' is discharged wsm, with all the Aff action run exactly once
133
+ let wsm = map (wrap <<< WidgetStep <<< pure <<< Right ) ws
134
+ -- TODO: We know the array is non-empty. We need something like foldl1WithIndex.
135
+ Tuple i e <- sequential (foldlWithIndex (\i r w ->
136
+ alt (parallel (map (Tuple i) w)) r) empty wscs)
137
+ -- TODO: All the Aff in ws is already discharged. Use a more efficient way than comb to process it
138
+ -- TODO: Also, more importantly, we would like to not have to cancel running fibers unless one of them returns a result
139
+ pure $ comb (fromMaybe wsm (updateAt i e wsm))
140
+
141
+ instance widgetSemigroup :: (Monoid v ) => Semigroup (Widget v a ) where
118
142
append w1 w2 = orr [w1, w2]
119
143
120
- instance widgetMonoid :: Monoid v => Monoid (Widget v a ) where
144
+ instance widgetMonoid :: ( Monoid v ) => Monoid (Widget v a ) where
121
145
mempty = empty
122
146
123
- instance widgetAlt :: Monoid v => Alt (Widget v ) where
147
+ instance widgetAlt :: ( Monoid v ) => Alt (Widget v ) where
124
148
alt = append
125
149
126
- instance widgetPlus :: Monoid v => Plus (Widget v ) where
150
+ instance widgetPlus :: ( Monoid v ) => Plus (Widget v ) where
127
151
empty = display mempty
128
152
129
- instance widgetAlternative :: Monoid v => Alternative (Widget v )
153
+ instance widgetAlternative :: ( Monoid v ) => Alternative (Widget v )
130
154
131
155
-- Pause for a negligible amount of time. Forces continuations to pass through the trampoline.
132
156
-- (Somewhat similar to calling `setTimeout` of zero in Javascript)
133
157
-- Avoids stack overflows in (pathological) cases where a widget calls itself repeatedly without any intervening widgets or effects.
134
158
-- E.g. -
135
159
-- BAD `counter n = if n < 10000 then counter (n+1) else pure n`
136
160
-- GOOD `counter n = if n < 10000 then (do pulse; counter (n+1)) else pure n`
137
- pulse :: forall v . Monoid v => Widget v Unit
161
+ pulse ::
162
+ forall v .
163
+ Monoid v =>
164
+ Widget v Unit
138
165
pulse = unsafeBlockingEffAction (pure unit)
139
166
140
167
mapView :: forall a v1 v2 . (v1 -> v2 ) -> Widget v1 a -> Widget v2 a
141
168
mapView f (Widget w) = Widget (hoistFree (mapViewStep f) w)
142
169
143
170
mapViewStep :: forall v1 v2 a . (v1 -> v2 ) -> WidgetStep v1 a -> WidgetStep v2 a
144
171
mapViewStep f (WidgetStep ws) = WidgetStep (map mod ws)
145
- where mod = map (\ws' -> ws' { view = f ws'.view })
172
+ where
173
+ mod = map (\ws' ->
174
+ ws' { view = f ws'.view
175
+ })
146
176
147
177
display :: forall a v . v -> Widget v a
148
178
display v = Widget (liftF (displayStep v))
149
179
150
180
-- Sync but Non blocking eff
151
- effAction :: forall a v . Effect a -> Widget v a
152
- effAction eff = unsafeBlockingEffAction eff -- affAction v $ liftEffect eff
181
+ effAction ::
182
+ forall a v .
183
+ Effect a ->
184
+ Widget v a
185
+ effAction eff = unsafeBlockingEffAction eff
153
186
154
187
-- Sync and blocking eff
155
188
-- WARNING: UNSAFE: This will block the UI rendering
156
- unsafeBlockingEffAction :: forall a v . Effect a -> Widget v a
189
+ unsafeBlockingEffAction ::
190
+ forall a v .
191
+ Effect a ->
192
+ Widget v a
157
193
unsafeBlockingEffAction eff = Widget $ liftF $ WidgetStep $ map Left eff
158
- -- eff >>= \a -> pure { view: v, cont: pure a }
159
194
160
195
-- Async aff
161
- affAction :: forall a v . v -> Aff a -> Widget v a
196
+ affAction ::
197
+ forall a v .
198
+ v ->
199
+ Aff a ->
200
+ Widget v a
162
201
affAction v aff = Widget $ liftF $ WidgetStep do
163
202
var <- EVar .empty
164
203
runAff_ (handler var) aff
@@ -168,52 +207,70 @@ affAction v aff = Widget $ liftF $ WidgetStep do
168
207
Just a -> Left a
169
208
Nothing -> Right { view: v, cont: liftAff (AVar .take var) }
170
209
where
171
- -- TODO: allow client code to handle aff failures
172
- handler _ (Left e) = log (" Aff failed - " <> show e)
173
- handler var (Right a) = void (EVar .tryPut a var)
210
+ -- TODO: allow client code to handle aff failures
211
+ handler _ (Left e) = log (" Aff failed - " <> show e)
212
+ handler var (Right a) = void (EVar .tryPut a var)
174
213
175
214
-- Async callback
176
- asyncAction :: forall v a . v -> ((Either Error a -> Effect Unit ) -> Effect (Effect Unit )) -> Widget v a
215
+ asyncAction ::
216
+ forall v a .
217
+ v ->
218
+ ((Either Error a -> Effect Unit ) -> Effect (Effect Unit )) ->
219
+ Widget v a
177
220
asyncAction v handler = affAction v (makeAff (map effectCanceler <<< handler))
178
221
179
- instance widgetMonadEff :: Monoid v => MonadEffect (Widget v ) where
222
+ instance widgetMonadEff :: ( Monoid v ) => MonadEffect (Widget v ) where
180
223
liftEffect = effAction
181
224
182
- instance widgetMonadAff :: Monoid v => MonadAff (Widget v ) where
225
+ instance widgetMonadAff :: ( Monoid v ) => MonadAff (Widget v ) where
183
226
liftAff = affAction mempty
184
227
185
228
-- Helpers for some very common use of unsafe blocking io
186
-
187
229
-- | Construct a widget from a primitive view event
188
- withViewEvent :: forall a v . ((a -> Effect Unit ) -> v ) -> Widget v a
230
+ withViewEvent ::
231
+ forall a v .
232
+ ((a -> Effect Unit ) -> v ) ->
233
+ Widget v a
189
234
withViewEvent mkView = Widget (liftF (WidgetStep (do
190
- v <- EVar .empty
191
- pure (Right { view: mkView (\a -> void (EVar .tryPut a v)), cont: liftAff (AVar .take v) })
192
- )))
235
+ v <- EVar .empty
236
+ pure (Right { view: mkView (\a ->
237
+ void (EVar .tryPut a v))
238
+ , cont: liftAff (AVar .take v)
239
+ }))))
193
240
194
241
-- | Construct a widget, by wrapping an existing widget in a view event
195
- wrapViewEvent :: forall a v . ((a -> Effect Unit ) -> v -> v ) -> Widget v a -> Widget v a
242
+ wrapViewEvent ::
243
+ forall a v .
244
+ ((a -> Effect Unit ) -> v -> v ) ->
245
+ Widget v a ->
246
+ Widget v a
196
247
wrapViewEvent mkView (Widget w) = Widget (wrapViewEvent' w)
197
248
where
198
- wrapViewEvent' w' =
199
- case resume w' of
200
- Left a -> pure a
201
- Right (WidgetStep wsm) -> wrap $ WidgetStep do
202
- ews <- wsm
203
- case ews of
204
- Left a -> pure (Left a)
205
- Right ws -> do
206
- var <- EVar .empty
207
- let eventHandler = (\a -> void (EVar .tryPut (pure a) var))
208
- let viewMapper = mkView eventHandler
209
- let view' = viewMapper ws.view
210
- let cont' = sequential (alt (parallel (liftAff (AVar .take var))) (parallel (map wrapViewEvent' ws.cont)))
211
- pure (Right {view: view', cont: cont'})
249
+ wrapViewEvent' w' = case resume w' of
250
+ Left a -> pure a
251
+ Right (WidgetStep wsm) -> wrap $ WidgetStep do
252
+ ews <- wsm
253
+ case ews of
254
+ Left a -> pure (Left a)
255
+ Right ws -> do
256
+ var <- EVar .empty
257
+ let eventHandler = (\a ->
258
+ void (EVar .tryPut (pure a) var))
259
+ let viewMapper = mkView eventHandler
260
+ let view' = viewMapper ws.view
261
+ let cont' = sequential (alt (parallel (liftAff (AVar .take var))) (parallel (map wrapViewEvent' ws.cont)))
262
+ pure (Right { view: view'
263
+ , cont: cont'
264
+ })
212
265
213
266
-- | Construct a widget with just props
214
- mkLeafWidget :: forall a v . ((a -> Effect Unit ) -> v ) -> Widget v a
267
+ mkLeafWidget ::
268
+ forall a v .
269
+ ((a -> Effect Unit ) -> v ) ->
270
+ Widget v a
215
271
mkLeafWidget mkView = Widget $ wrap $ WidgetStep do
216
272
var <- EVar .empty
217
- let view' = mkView (\a -> void (EVar .tryPut (pure a) var))
273
+ let view' = mkView (\a ->
274
+ void (EVar .tryPut (pure a) var))
218
275
let cont' = liftAff (AVar .take var)
219
- pure (Right {view: view', cont: cont'})
276
+ pure (Right { view: view', cont: cont' })
0 commit comments