@@ -3,14 +3,15 @@ module Control.Stream
3 , EffStream
3 , EffStream
7 , Scheduler
10 , Scheduler
9 , ScheduledTask
12 , ScheduledTask
10 , Disposable
13 , Disposable
14 -- Scheduler-related functions and values
15 -- Scheduler-related functions and values
15 , defaultScheduler
16 , defaultScheduler
16 , eventTask
17 , eventTask
@@ -46,29 +47,39 @@ module Control.Stream
46 , constant
47 , constant
48 , startWith
49 , startWith
49 -- Stream factories
56 -- Stream factories
51 , fromArray
58 , fromArray
53 , periodic
61 , periodic
65+import Control.Alt ((<|>))
57import Control.Applicative (class Applicative)
66import Control.Applicative (class Applicative)
58import Control.Apply (class Apply)
67import Control.Apply (class Apply)
59import Control.Bind (class Bind)
68import Control.Bind (class Bind)
60import Control.Category (id)
69import Control.Category (id)
61import Control.Monad (class Monad)
70import Control.Monad (class Monad)
62−import Control.Monad.Eff (Eff, Pure)
71+import Control.Monad.Eff (Eff, Pure, runPure)
63import Control.Monad.Eff.Ref (Ref, modifyRef', newRef, readRef)
72import Control.Monad.Eff.Ref (Ref, modifyRef', newRef, readRef)
64import Control.Monad.Eff.Unsafe (unsafeCoerceEff, unsafePerformEff)
73import Control.Monad.Eff.Unsafe (unsafeCoerceEff, unsafePerformEff)
65import Control.MonadPlus (class Alt, class Plus)
74import Control.MonadPlus (class Alt, class Plus)
66−import Data.Array (snoc)
75+import Data.Eq (class Eq, eq)
67import Data.Function (flip, ($))
76import Data.Function (flip, ($))
68import Data.Functor (class Functor, map)
77import Data.Functor (class Functor, map)
78+import Data.Maybe (Maybe(Just, Nothing), fromJust, isJust)
69import Data.Monoid (class Monoid)
79import Data.Monoid (class Monoid)
70import Data.Semigroup (class Semigroup)
80import Data.Semigroup (class Semigroup)
71import Data.Unit (Unit, unit)
81import Data.Unit (Unit, unit)
82+import Partial.Unsafe (unsafePartial)
73newtype Time = Time Int
84newtype Time = Time Int
@@ -78,9 +89,13 @@ type EffStream e a = Eff (stream :: STREAM | e) a
79newtype Stream a = Stream { source :: Source a }
90newtype Stream a = Stream { source :: Source a }
81−type Source a = { run :: Sink a -> Scheduler -> Disposable }
92+newtype Source a = Source { run :: RunFn a }
83−type Sink a =
94+type RunFn a = Sink a -> Scheduler -> Disposable
95+type EventFn a = Time -> a -> Unit
96+type EndFn = Time -> Unit
84 { event :: Time -> a -> Unit
99 { event :: Time -> a -> Unit
85 , end :: Time -> Unit
100 , end :: Time -> Unit
@@ -107,9 +122,6 @@ type ScheduledTask =
108type Disposable = { dispose :: Pure Unit }
123type Disposable = { dispose :: Pure Unit }
110−type EventFn a b = (Sink b -> Scheduler -> Time -> a -> Unit)
111−type EndFn a = (Sink a -> Scheduler -> Time -> Unit)
113instance functorStream :: Functor Stream where
125instance functorStream :: Functor Stream where
114 map = _map
126 map = _map
@@ -138,36 +150,37 @@ instance plusStream :: Plus Stream where
139-- Stream-related helpers
151-- Stream-related helpers
140createStream :: forall a. (Sink a -> Scheduler -> Disposable) -> Stream a
152createStream :: forall a. (Sink a -> Scheduler -> Disposable) -> Stream a
141−createStream run = Stream { source: { run } }
153+createStream run = Stream { source: Source { run } }
143getSource :: forall a. Stream a -> Source a
155getSource :: forall a. Stream a -> Source a
144−getSource stream = case stream of Stream a -> a.source
156+getSource (Stream stream) = stream.source
158+runSource :: forall a. Source a -> Sink a -> Scheduler -> Disposable
159+runSource (Source source) sink scheduler = source.run sink scheduler
146−runSource :: forall a. Stream a -> Sink a -> Scheduler -> Disposable
161+runStream :: forall a. Stream a -> Sink a -> Scheduler -> Disposable
147−runSource stream sink scheduler = (getSource stream).run sink scheduler
162+runStream stream sink scheduler = runSource (getSource stream) sink scheduler
149createSink :: forall a. (Time -> a -> Unit) -> (Time -> Unit) -> Sink a
164createSink :: forall a. (Time -> a -> Unit) -> (Time -> Unit) -> Sink a
150−createSink event end = { event, end }
165+createSink event end = Sink { event, end }
152−createCombinator :: forall a b. EventFn a b -> EndFn b -> Stream a -> Stream b
167+createCombinator :: forall a b. (Sink b -> Scheduler -> EventFn a) -> (Sink b -> Scheduler -> EndFn) -> Stream a -> Stream b
153createCombinator event end stream = createStream runCombinator
168createCombinator event end stream = createStream runCombinator
155 runCombinator :: Sink b -> Scheduler -> Disposable
170 runCombinator :: Sink b -> Scheduler -> Disposable
156 runCombinator sink scheduler =
171 runCombinator sink scheduler =
157− runSource stream (createSink (event sink scheduler) (end sink scheduler)) scheduler
172+ runStream stream (createSink (event sink scheduler) (end sink scheduler)) scheduler
159−createEventCombinator :: forall a b. EventFn a b -> Stream a -> Stream b
174+createEventCombinator :: forall a b. (Sink b -> Scheduler -> EventFn a) -> Stream a -> Stream b
160createEventCombinator event stream = createCombinator event end stream
175createEventCombinator event stream = createCombinator event end stream
163− end sink scheduler time =
177+ end (Sink sink) (Scheduler scheduler) time = sink.end time
166−createEndCombinator :: forall a. EndFn a -> Stream a -> Stream a
179+createEndCombinator :: forall a. (Sink a -> Scheduler -> EndFn) -> Stream a -> Stream a
167createEndCombinator end stream = createCombinator event end stream
180createEndCombinator end stream = createCombinator event end stream
169− event :: EventFn a a
182+ event :: Sink a -> Scheduler -> EventFn a
170− event sink scheduler time value = sink.event time value
183+ event (Sink sink) scheduler time value = sink.event time value
172-- Stream factories
185-- Stream factories
173just :: forall a. a -> Stream a
186just :: forall a. a -> Stream a
@@ -192,7 +205,7 @@ runFromArray :: forall a. Array a -> Sink a -> Scheduler -> Disposable
192runFromArray arr sink scheduler = scheduleTasks tasks scheduler
205runFromArray arr sink scheduler = scheduleTasks tasks scheduler
194 tasks :: Array Task
207 tasks :: Array Task
195− tasks = snoc eventTasks (endTask sink)
208+ tasks = eventTasks <|> [ (endTask sink) ]
197 eventTasks :: Array Task
210 eventTasks :: Array Task
198 eventTasks = map (flip eventTask sink) arr
211 eventTasks = map (flip eventTask sink) arr
@@ -201,39 +214,34 @@ periodic :: Number -> Stream Unit
201periodic period = createStream (runPeriodic period)
214periodic period = createStream (runPeriodic period)
203runPeriodic :: Number -> Sink Unit -> Scheduler -> Disposable
216runPeriodic :: Number -> Sink Unit -> Scheduler -> Disposable
204−runPeriodic period sink scheduler = { dispose: scheduledTask.dispose }
217+runPeriodic period sink (Scheduler scheduler) = { dispose: scheduledTask.dispose }
206− p = case scheduler of Scheduler a -> a.periodic
207− scheduledTask = p period (eventTask unit sink)
219+ scheduledTask = scheduler.periodic period (eventTask unit sink)
209-- combinators
221-- combinators
210_map :: forall a b. (a -> b) -> Stream a -> Stream b
222_map :: forall a b. (a -> b) -> Stream a -> Stream b
211_map f stream = createEventCombinator mapEvent stream
223_map f stream = createEventCombinator mapEvent stream
213− mapEvent :: EventFn a b
214− mapEvent sink scheduler time value = sink.event time (f value)
225+ mapEvent (Sink sink) (Scheduler scheduler) time value = sink.event time (f value)
216filter :: forall a. (a -> Boolean) -> Stream a -> Stream a
227filter :: forall a. (a -> Boolean) -> Stream a -> Stream a
217filter predicate stream = createEventCombinator event stream
228filter predicate stream = createEventCombinator event stream
219− event :: EventFn a a
220− event sink scheduler time value = if predicate value
230+ event (Sink sink) (Scheduler scheduler) time value = if predicate value
221 then sink.event time value
231 then sink.event time value
222 else unit
232 else unit
224tapEvent :: forall e a. (a -> EffStream e Unit) -> Stream a -> Stream a
234tapEvent :: forall e a. (a -> EffStream e Unit) -> Stream a -> Stream a
225tapEvent f stream = createEventCombinator event stream
235tapEvent f stream = createEventCombinator event stream
227− event :: EventFn a a
228− event sink scheduler time value = sink.event time value
237+ event (Sink sink) (Scheduler scheduler) time value = sink.event time value
229 where -- find a better way to perform these side effects
238 where -- find a better way to perform these side effects
230 x = unsafePerformEff (f value)
239 x = unsafePerformEff (f value)
232tapEnd :: forall e a. EffStream e Unit -> Stream a -> Stream a
241tapEnd :: forall e a. EffStream e Unit -> Stream a -> Stream a
233tapEnd f stream = createEndCombinator end stream
242tapEnd f stream = createEndCombinator end stream
236− end sink scheduler time = sink.end time
244+ end (Sink sink) (Scheduler scheduler) time = sink.end time
237 where -- find a better way to perform these side effects
245 where -- find a better way to perform these side effects
238 x = unsafePerformEff f
246 x = unsafePerformEff f
@@ -243,18 +251,51 @@ startWith value stream = concat (just value) stream
243constant :: forall a b. b -> Stream a -> Stream b
251constant :: forall a b. b -> Stream a -> Stream b
244constant value stream = createEventCombinator constantEvent stream
252constant value stream = createEventCombinator constantEvent stream
246− constantEvent sink scheduler time x = sink.event time value
254+ constantEvent (Sink sink) (Scheduler scheduler) time x = sink.event time value
248scan :: forall a b. (b -> a -> b) -> b -> Stream a -> Stream b
256scan :: forall a b. (b -> a -> b) -> b -> Stream a -> Stream b
249scan f seed stream = startWith seed $ createEventCombinator scanEvent stream
257scan f seed stream = startWith seed $ createEventCombinator scanEvent stream
251 state = createState seed
260 state = createState seed
253 scanEvent :: Sink b -> Scheduler -> Time -> a -> Unit
262 scanEvent :: Sink b -> Scheduler -> Time -> a -> Unit
254− scanEvent sink scheduler time value = sink.event time (state.set \acc -> f acc value)
263+ scanEvent (Sink sink) (Scheduler scheduler) time value = sink.event time (state.set \acc -> f acc value)
265+skipRepeats :: forall a. (Eq a) => Stream a -> Stream a
266+skipRepeats = skipRepeatsWith eq
268+sample :: forall a b c. (a -> b -> c) -> Stream a -> Stream b -> Stream c
269+sample f sampler stream = createStream $ runSample (createState Nothing)
271+ runSample :: State (Maybe b) -> Sink c -> Scheduler -> Disposable
272+ runSample state sink scheduler = disposeAll
273+ [ runStream stream (createHoldSink state) scheduler
274+ , runStream sampler (createSampleSink state sink f) scheduler
277+createHoldSink :: forall a. State (Maybe a) -> Sink a
278+createHoldSink state = createSink event end
280+ event time value = always unit (state.set \_ -> Just value)
283+createSampleSink :: forall a b c. State (Maybe b) -> Sink c -> (a -> b -> c) -> Sink a
284+createSampleSink state (Sink sink) f = createSink event end
286+ end time = sink.end time
288+ if isJust (runPure state.get)
289+ then sink.event time $ f value (unsafePartial $ fromJust (runPure state.get))
292+always :: forall a b. a -> b -> a
256-- find a better way to perform these side effects
295-- find a better way to perform these side effects
257−createState :: forall a. a -> { get :: Pure a, set :: (a -> a) -> a }
296+type State a = { get:: Pure a, set :: (a -> a) -> a }
298+createState :: forall a. a -> State a
258createState seed = { set, get }
299createState seed = { set, get }
260 ref :: Ref a
301 ref :: Ref a
@@ -290,3 +331,7 @@ foreign import continueWith :: forall a. (Unit -> Stream a) -> Stream a -> Strea
290foreign import concat :: forall a. Stream a -> Stream a -> Stream a
331foreign import concat :: forall a. Stream a -> Stream a -> Stream a
291foreign import merge :: forall a. Array (Stream a) -> Stream a
332foreign import merge :: forall a. Array (Stream a) -> Stream a
292foreign import switch :: forall a. Stream (Stream a) -> Stream a
333foreign import switch :: forall a. Stream (Stream a) -> Stream a
334+foreign import multicast :: forall a. Stream a -> Stream a
335+foreign import hold :: forall a. Int -> Stream a -> Stream a
336+foreign import skipRepeatsWith :: forall a. (a -> a -> Boolean) -> Stream a -> Stream a
337+foreign import delay :: forall a. Number -> Stream a -> Stream a