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

Commit 122e40e

Browse files
Tom Hardingpaf31
authored andcommitted
Add gateBy and gate to FRP.Event.Time (#21)
* Add `gateBy` and `gate` to `FRP.Event.Time` Previously, the functions only existed for `Behavior`. This PR adds them to `Event` as well. * Fix comments from review Put the functions in the wrong place. Oops. This commit moves the `gate`-related functions from `FRP.Event.Time` to `FRP.Event.Class`, and exports them. * Final review changes, merging in blocking As per the other PR, I've combined these two because there's some interdependence. This implements the mentioned changes, and should now be up-to-date with both PRs. * Replace "initial gating value" with `Maybe` Previously, the function required an initial value. This wasn't great if you didn't have such a value to hand, and has hence been removed in favour of a `Maybe` in the predicate. The result is much neater :)
1 parent 23ca2e3 commit 122e40e

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

src/FRP/Event/Class.purs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ module FRP.Event.Class
99
, sampleOn_
1010
, keepLatest
1111
, fix
12+
, gate
13+
, gateBy
1214
, module Data.Filterable
1315
) where
1416

1517
import Prelude
1618

17-
import Control.Alternative (class Alternative)
18-
import Data.Filterable (class Filterable, filterMap)
19-
import Data.Maybe (Maybe(..))
19+
import Control.Alternative (class Alternative, (<|>))
20+
import Data.Filterable (class Filterable, filterMap, filtered)
21+
import Data.Maybe (Maybe(..), fromMaybe)
2022
import Data.Monoid (class Monoid, mempty)
2123
import Data.Tuple (Tuple(..), snd)
2224

@@ -67,3 +69,24 @@ mapAccum f xs acc = filterMap snd
6769
-- | the second event.
6870
sampleOn_ :: forall event a b. IsEvent event => event a -> event b -> event a
6971
sampleOn_ a b = sampleOn a (b $> id)
72+
73+
-- | Sample the events that are fired while a boolean event is true. Note that,
74+
-- | until the boolean event fires, it will be assumed to be `false`, and events
75+
-- | will be blocked.
76+
gate :: forall a event. IsEvent event => event Boolean -> event a -> event a
77+
gate = gateBy (\x _ -> fromMaybe false x)
78+
79+
-- | Generalised form of `gateBy`, allowing for any predicate between the two
80+
-- | events. Until a value from the first event is received, `Nothing` will be
81+
-- | passed to the predicate.
82+
gateBy
83+
:: forall a b event
84+
. IsEvent event
85+
=> (Maybe a -> b -> Boolean)
86+
-> event a
87+
-> event b
88+
-> event b
89+
gateBy f sampled
90+
= filtered
91+
<<< sampleOn (pure Nothing <|> (Just <$> sampled))
92+
<<< map \x p -> if f p x then Just x else Nothing

src/FRP/Event/Time.purs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ module FRP.Event.Time
44
, withTime
55
) where
66

7+
import Data.Maybe (Maybe, maybe)
78
import Data.Unit (Unit)
89
import FRP.Event (Event)
10+
import FRP.Event.Class (fix, gateBy)
11+
import Prelude ((+), (<), map)
912

1013
-- | Create an event which fires every specified number of milliseconds.
1114
foreign import interval :: Int -> Event Int
@@ -15,3 +18,38 @@ foreign import animationFrame :: Event Unit
1518

1619
-- | Create an event which reports the current time in milliseconds since the epoch.
1720
foreign import withTime :: forall a. Event a -> Event { value :: a, time :: Number }
21+
22+
-- | On each event, ignore subsequent events for a given number of milliseconds.
23+
debounce :: forall a. Number -> Event a -> Event a
24+
debounce period = debounceWith (map { period, value: _ })
25+
26+
-- | Provided an input event and transformation, block the input event for the
27+
-- | duration of the specified period on each output.
28+
debounceWith
29+
:: forall a b.
30+
(Event a -> Event { period :: Number, value :: b })
31+
-> Event a
32+
-> Event b
33+
debounceWith process event
34+
= fix \allowed ->
35+
let
36+
processed :: Event { period :: Number, value :: b }
37+
processed = process allowed
38+
39+
expiries :: Event Number
40+
expiries =
41+
map (\{ time, value } -> time + value)
42+
(withTime (map _.period processed))
43+
44+
comparison :: forall r. Maybe Number -> { time :: Number | r } -> Boolean
45+
comparison a b = maybe true (_ < b.time) a
46+
47+
unblocked :: Event { time :: Number, value :: a }
48+
unblocked = gateBy comparison expiries stamped
49+
in
50+
{ input: map _.value unblocked
51+
, output: map _.value processed
52+
}
53+
where
54+
stamped :: Event { time :: Number, value :: a }
55+
stamped = withTime event

0 commit comments

Comments
 (0)