Skip to content
This repository was archived by the owner on Feb 2, 2021. It is now read-only.

Commit a16e1a8

Browse files
authored
Add switcher (#17)
* WIP: switcher * Mouse position and buttons need to be 'hot' * Extract fixE * Make key events hot * Move keepLatest into IsEvent class * Better switcher example
1 parent 7123ba0 commit a16e1a8

File tree

21 files changed

+389
-80
lines changed

21 files changed

+389
-80
lines changed

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"purescript-prelude": "^3.0.0",
2626
"purescript-eff": "^3.0.0",
2727
"purescript-sets": "^3.0.0",
28-
"purescript-filterable": "^2.3.0"
28+
"purescript-filterable": "^2.3.0",
29+
"purescript-nullable": "^3.0.0"
2930
},
3031
"devDependencies": {
3132
"purescript-math": "^2.0.0",

generated-docs/FRP/Behavior.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ Create a `Behavior` which is updated when an `Event` fires, by providing
8484
an initial value and a function to combine the current value with a new event
8585
to create a new value.
8686

87+
#### `switcher`
88+
89+
``` purescript
90+
switcher :: forall a. Behavior a -> Event (Behavior a) -> Behavior a
91+
```
92+
93+
Switch `Behavior`s based on an `Event`.
94+
8795
#### `integral`
8896

8997
``` purescript
@@ -211,7 +219,7 @@ Compute a fixed point
211219
#### `animate`
212220

213221
``` purescript
214-
animate :: forall scene eff. ABehavior Event scene -> (scene -> Eff (frp :: FRP | eff) Unit) -> Eff (frp :: FRP | eff) Unit
222+
animate :: forall scene eff. ABehavior Event scene -> (scene -> Eff (frp :: FRP | eff) Unit) -> Eff (frp :: FRP | eff) (Eff (frp :: FRP | eff) Unit)
215223
```
216224

217225
Animate a `Behavior` by providing a rendering function.

generated-docs/FRP/Behavior/Keyboard.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,12 @@ keys :: Behavior (Set Int)
88

99
A `Behavior` which reports the keys which are currently pressed.
1010

11+
#### `key`
12+
13+
``` purescript
14+
key :: Int -> Behavior Boolean
15+
```
16+
17+
A `Behavior` which reports whether a specific key is currently pressed.
18+
1119

generated-docs/FRP/Event.md

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
## Module FRP.Event
22

3+
#### `fix`
4+
5+
``` purescript
6+
fix :: forall i o. (Event i -> { input :: Event i, output :: Event o }) -> Event o
7+
```
8+
9+
Compute a fixed point
10+
311
#### `fold`
412

513
``` purescript
@@ -38,6 +46,7 @@ Events are consumed by providing a callback using the `subscribe` function.
3846
##### Instances
3947
``` purescript
4048
Functor Event
49+
Filterable Event
4150
Apply Event
4251
Applicative Event
4352
Alt Event
@@ -54,49 +63,84 @@ IsEvent Event
5463
never :: forall a. Event a
5564
```
5665

57-
#### `filter`
66+
#### `keepLatest`
5867

5968
``` purescript
60-
filter :: forall a. (a -> Boolean) -> Event a -> Event a
69+
keepLatest :: forall a. Event (Event a) -> Event a
6170
```
6271

63-
Create an `Event` which only fires when a predicate holds.
72+
Flatten a nested `Event`, reporting values only from the most recent
73+
inner `Event`.
6474

6575
#### `subscribe`
6676

6777
``` purescript
68-
subscribe :: forall eff a r. Event a -> (a -> Eff (frp :: FRP | eff) r) -> Eff (frp :: FRP | eff) Unit
78+
subscribe :: forall eff a r. Event a -> (a -> Eff (frp :: FRP | eff) r) -> Eff (frp :: FRP | eff) (Eff (frp :: FRP | eff) Unit)
6979
```
7080

7181
Subscribe to an `Event` by providing a callback.
7282

73-
#### `create`
83+
`subscribe` returns a canceller function.
84+
85+
86+
### Re-exported from Data.Filterable:
87+
88+
#### `Filterable`
7489

7590
``` purescript
76-
create :: forall eff a. Eff (frp :: FRP | eff) { event :: Event a, push :: a -> Eff (frp :: FRP | eff) Unit }
91+
class (Functor f) <= Filterable f where
92+
filterMap :: forall a b. (a -> Maybe b) -> f a -> f b
7793
```
7894

79-
Create an event and a function which supplies a value to that event.
95+
`Filterable` represents data structures which can be _partitioned_/_filtered_.
8096

97+
- `partitionMap` - partition a data structure based on an either predicate.
98+
- `partition` - partition a data structure based on boolean predicate.
99+
- `filterMap` - map over a data structure and filter based on a maybe.
100+
- `filter` - filter a data structure based on a boolean.
101+
102+
Laws:
103+
- `map f ≡ filterMap (Just <<< f)`
104+
- `filter ≡ filterMap <<< maybeBool`
105+
- `filterMap p ≡ filter (isJust <<< p)`
106+
107+
Default implementations are provided by the following functions:
108+
109+
- `partitionDefault`
110+
- `partitionDefaultFilter`
111+
- `partitionDefaultFilterMap`
112+
- `filterDefault`
113+
- `filterDefaultPartition`
114+
- `filterDefaultPartitionMap`
115+
116+
##### Instances
117+
``` purescript
118+
Filterable Array
119+
Filterable Maybe
120+
(Monoid m) => Filterable (Either m)
121+
Filterable List
122+
(Ord k) => Filterable (Map k)
123+
```
81124

82125
### Re-exported from FRP.Event.Class:
83126

84127
#### `IsEvent`
85128

86129
``` purescript
87-
class (Alternative event) <= IsEvent event where
130+
class (Alternative event, Filterable event) <= IsEvent event where
88131
fold :: forall a b. (a -> b -> b) -> event a -> b -> event b
89-
mapMaybe :: forall a b. (a -> Maybe b) -> event a -> event b
90132
sampleOn :: forall a b. event a -> event (a -> b) -> event b
133+
fix :: forall i o. (event i -> { input :: event i, output :: event o }) -> event o
91134
```
92135

93136
Functions which an `Event` type should implement, so that
94137
`Behavior`s can be defined in terms of any such event type:
95138

96139
- `fold`: combines incoming values using the specified function,
97140
starting with the specific initial value.
98-
- `mapMaybe`: discards incoming values which do not satisfy a predicate.
99141
- `sampleOn`: samples an event at the times when a second event fires.
142+
- `fix`: compute a fixed point, by feeding output events back in as
143+
inputs.
100144

101145
#### `withLast`
102146

generated-docs/FRP/Event/Class.md

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@
33
#### `IsEvent`
44

55
``` purescript
6-
class (Alternative event) <= IsEvent event where
6+
class (Alternative event, Filterable event) <= IsEvent event where
77
fold :: forall a b. (a -> b -> b) -> event a -> b -> event b
8-
mapMaybe :: forall a b. (a -> Maybe b) -> event a -> event b
98
sampleOn :: forall a b. event a -> event (a -> b) -> event b
9+
fix :: forall i o. (event i -> { input :: event i, output :: event o }) -> event o
1010
```
1111

1212
Functions which an `Event` type should implement, so that
1313
`Behavior`s can be defined in terms of any such event type:
1414

1515
- `fold`: combines incoming values using the specified function,
1616
starting with the specific initial value.
17-
- `mapMaybe`: discards incoming values which do not satisfy a predicate.
1817
- `sampleOn`: samples an event at the times when a second event fires.
18+
- `fix`: compute a fixed point, by feeding output events back in as
19+
inputs.
1920

2021
#### `folded`
2122

@@ -66,3 +67,42 @@ at the times when the second event fires, ignoring the values produced by
6667
the second event.
6768

6869

70+
### Re-exported from Data.Filterable:
71+
72+
#### `Filterable`
73+
74+
``` purescript
75+
class (Functor f) <= Filterable f where
76+
filterMap :: forall a b. (a -> Maybe b) -> f a -> f b
77+
```
78+
79+
`Filterable` represents data structures which can be _partitioned_/_filtered_.
80+
81+
- `partitionMap` - partition a data structure based on an either predicate.
82+
- `partition` - partition a data structure based on boolean predicate.
83+
- `filterMap` - map over a data structure and filter based on a maybe.
84+
- `filter` - filter a data structure based on a boolean.
85+
86+
Laws:
87+
- `map f ≡ filterMap (Just <<< f)`
88+
- `filter ≡ filterMap <<< maybeBool`
89+
- `filterMap p ≡ filter (isJust <<< p)`
90+
91+
Default implementations are provided by the following functions:
92+
93+
- `partitionDefault`
94+
- `partitionDefaultFilter`
95+
- `partitionDefaultFilterMap`
96+
- `filterDefault`
97+
- `filterDefaultPartition`
98+
- `filterDefaultPartitionMap`
99+
100+
##### Instances
101+
``` purescript
102+
Filterable Array
103+
Filterable Maybe
104+
(Monoid m) => Filterable (Either m)
105+
Filterable List
106+
(Ord k) => Filterable (Map k)
107+
```
108+

generated-docs/FRP/Event/Keyboard.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,12 @@ up :: Event Int
1616

1717
Create an `Event` which fires when a key is released
1818

19+
#### `withKeys`
20+
21+
``` purescript
22+
withKeys :: forall a. Event a -> Event { value :: a, keys :: Array Int }
23+
```
24+
25+
Create an event which also returns the current pressed keycodes.
26+
1927

generated-docs/FRP/Event/Mouse.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,20 @@ up :: Event Int
2424

2525
Create an `Event` which fires when a mouse button is released
2626

27+
#### `withPosition`
28+
29+
``` purescript
30+
withPosition :: forall a. Event a -> Event { value :: a, pos :: Nullable { x :: Int, y :: Int } }
31+
```
32+
33+
Create an event which also returns the current mouse position.
34+
35+
#### `withButtons`
36+
37+
``` purescript
38+
withButtons :: forall a. Event a -> Event { value :: a, buttons :: Array Int }
39+
```
40+
41+
Create an event which also returns the current mouse buttons.
42+
2743

generated-docs/FRP/Event/Semantic.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ Functor (Semantic time)
118118
(Bounded time) => Alternative (Semantic time)
119119
(Ord time, Semigroup a) => Semigroup (Semantic time a)
120120
(Bounded time, Monoid a) => Monoid (Semantic time a)
121+
Filterable (Semantic time)
121122
(Bounded time) => IsEvent (Semantic time)
122123
```
123124

src/FRP/Behavior.purs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module FRP.Behavior
99
, gate
1010
, gateBy
1111
, unfold
12+
, switcher
1213
, integral
1314
, integral'
1415
, derivative
@@ -26,14 +27,13 @@ import Prelude
2627
import Control.Alt (alt)
2728
import Control.Apply (lift2)
2829
import Control.Monad.Eff (Eff)
29-
import Control.Monad.Eff.Unsafe (unsafePerformEff)
3030
import Data.Filterable (filtered)
3131
import Data.Function (applyFlipped)
3232
import Data.Maybe (Maybe(..))
3333
import Data.Monoid (class Monoid, mempty)
3434
import Data.Tuple (Tuple(Tuple))
3535
import FRP (FRP)
36-
import FRP.Event (class IsEvent, Event, create, fold, sampleOn, subscribe, withLast)
36+
import FRP.Event (class IsEvent, Event, fix, fold, keepLatest, sampleOn, subscribe, withLast)
3737
import FRP.Event.Time (animationFrame)
3838

3939
-- | `ABehavior` is the more general type of `Behavior`, which is parameterized
@@ -92,6 +92,11 @@ sampleBy f b e = sample (map f b) (map applyFlipped e)
9292
sample_ :: forall event a b. IsEvent event => ABehavior event a -> event b -> event a
9393
sample_ = sampleBy const
9494

95+
-- | Switch `Behavior`s based on an `Event`.
96+
switcher :: forall a. Behavior a -> Event (Behavior a) -> Behavior a
97+
switcher b0 e = behavior \s ->
98+
keepLatest (pure (sample b0 s) `alt` map (\b -> sample b s) e)
99+
95100
-- | Sample a `Behavior` on some `Event` by providing a predicate function.
96101
gateBy :: forall event p a. IsEvent event => (p -> a -> Boolean) -> ABehavior event p -> event a -> event a
97102
gateBy f ps xs = filtered (sampleBy (\p x -> if f p x then Just x else Nothing) ps xs)
@@ -189,11 +194,11 @@ derivative' = derivative (_ $ id)
189194

190195
-- | Compute a fixed point
191196
fixB :: forall a. a -> (ABehavior Event a -> ABehavior Event a) -> ABehavior Event a
192-
fixB a f = behavior \s -> unsafePerformEff do
193-
{ event, push } <- create
194-
let b = f (step a event)
195-
subscribe (sample_ b s) push
196-
pure (sampleOn event s)
197+
fixB a f =
198+
behavior \s ->
199+
fix \event ->
200+
let b = f (step a event)
201+
in { input: sample_ b s, output: sampleOn event s }
197202

198203
-- | Solve a first order differential equation of the form
199204
-- |
@@ -280,5 +285,5 @@ animate
280285
:: forall scene eff
281286
. ABehavior Event scene
282287
-> (scene -> Eff (frp :: FRP | eff) Unit)
283-
-> Eff (frp :: FRP | eff) Unit
288+
-> Eff (frp :: FRP | eff) (Eff (frp :: FRP | eff) Unit)
284289
animate scene render = subscribe (sample_ scene animationFrame) render

src/FRP/Behavior/Keyboard.purs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
module FRP.Behavior.Keyboard
22
( keys
3+
, key
34
) where
45

56
import Prelude
67

7-
import Control.Alt ((<|>))
88
import Data.Set as Set
9-
import FRP.Behavior (Behavior, unfold)
10-
import FRP.Event.Keyboard (up, down)
9+
import FRP.Behavior (Behavior, behavior)
10+
import FRP.Event.Keyboard (withKeys)
1111

1212
-- | A `Behavior` which reports the keys which are currently pressed.
1313
keys :: Behavior (Set.Set Int)
14-
keys = unfold id (Set.insert <$> down <|> Set.delete <$> up) Set.empty
14+
keys = behavior \e -> map (\{ value, keys: ks } -> value (Set.fromFoldable ks)) (withKeys e)
15+
16+
-- | A `Behavior` which reports whether a specific key is currently pressed.
17+
key :: Int -> Behavior Boolean
18+
key k = Set.member k <$> keys

0 commit comments

Comments
 (0)