@@ -3,14 +3,15 @@ module Control.Stream
33 , EffStream
44 , Stream
55 , Source
6+ , EventFn
7+ , EndFn
8+ , RunFn
69 , Sink
710 , Scheduler
811 , Task
912 , ScheduledTask
1013 , Disposable
1114 , Time
12− , EventFn
13− , EndFn
1415 -- Scheduler-related functions and values
1516 , defaultScheduler
1617 , eventTask
@@ -46,29 +47,39 @@ module Control.Stream
4647 , constant
4748 , scan
4849 , startWith
50+ , multicast
51+ , hold
52+ , skipRepeats
53+ , skipRepeatsWith
54+ , delay
55+ , sample
4956 -- Stream factories
5057 , just
5158 , fromArray
5259 , empty
60+ , never
5361 , periodic
5462 )
5563 where
5664
65+import Control.Alt ((<|>))
5766import Control.Applicative (class Applicative)
5867import Control.Apply (class Apply)
5968import Control.Bind (class Bind)
6069import Control.Category (id)
6170import Control.Monad (class Monad)
62−import Control.Monad.Eff (Eff, Pure)
71+import Control.Monad.Eff (Eff, Pure, runPure)
6372import Control.Monad.Eff.Ref (Ref, modifyRef', newRef, readRef)
6473import Control.Monad.Eff.Unsafe (unsafeCoerceEff, unsafePerformEff)
6574import Control.MonadPlus (class Alt, class Plus)
66−import Data.Array (snoc)
75+import Data.Eq (class Eq, eq)
6776import Data.Function (flip, ($))
6877import Data.Functor (class Functor, map)
78+import Data.Maybe (Maybe(Just, Nothing), fromJust, isJust)
6979import Data.Monoid (class Monoid)
7080import Data.Semigroup (class Semigroup)
7181import Data.Unit (Unit, unit)
82+import Partial.Unsafe (unsafePartial)
7283
7384newtype Time = Time Int
7485
@@ -78,9 +89,13 @@ type EffStream e a = Eff (stream :: STREAM | e) a
7889
7990newtype Stream a = Stream { source :: Source a }
8091
81−type Source a = { run :: Sink a -> Scheduler -> Disposable }
92+newtype Source a = Source { run :: RunFn a }
8293
83−type Sink a =
94+type RunFn a = Sink a -> Scheduler -> Disposable
95+type EventFn a = Time -> a -> Unit
96+type EndFn = Time -> Unit
97+
98+newtype Sink a = Sink
8499 { event :: Time -> a -> Unit
85100 , end :: Time -> Unit
86101 }
@@ -107,9 +122,6 @@ type ScheduledTask =
107122
108123type Disposable = { dispose :: Pure Unit }
109124
110−type EventFn a b = (Sink b -> Scheduler -> Time -> a -> Unit)
111−type EndFn a = (Sink a -> Scheduler -> Time -> Unit)
112−
113125instance functorStream :: Functor Stream where
114126 map = _map
115127
@@ -138,36 +150,37 @@ instance plusStream :: Plus Stream where
138150
139151-- Stream-related helpers
140152createStream :: forall a. (Sink a -> Scheduler -> Disposable) -> Stream a
141−createStream run = Stream { source: { run } }
153+createStream run = Stream { source: Source { run } }
142154
143155getSource :: forall a. Stream a -> Source a
144−getSource stream = case stream of Stream a -> a.source
156+getSource (Stream stream) = stream.source
145157
146−runSource :: forall a. Stream a -> Sink a -> Scheduler -> Disposable
147−runSource stream sink scheduler = (getSource stream).run sink scheduler
158+runSource :: forall a. Source a -> Sink a -> Scheduler -> Disposable
159+runSource (Source source) sink scheduler = source.run sink scheduler
160+
161+runStream :: forall a. Stream a -> Sink a -> Scheduler -> Disposable
162+runStream stream sink scheduler = runSource (getSource stream) sink scheduler
148163
149164createSink :: forall a. (Time -> a -> Unit) -> (Time -> Unit) -> Sink a
150−createSink event end = { event, end }
165+createSink event end = Sink { event, end }
151166
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
153168createCombinator event end stream = createStream runCombinator
154169 where
155170 runCombinator :: Sink b -> Scheduler -> Disposable
156171 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
158173
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
160175createEventCombinator event stream = createCombinator event end stream
161176 where
162− end :: EndFn b
163− end sink scheduler time =
164− sink.end time
177+ end (Sink sink) (Scheduler scheduler) time = sink.end time
165178
166−createEndCombinator :: forall a. EndFn a -> Stream a -> Stream a
179+createEndCombinator :: forall a. (Sink a -> Scheduler -> EndFn) -> Stream a -> Stream a
167180createEndCombinator end stream = createCombinator event end stream
168181 where
169− event :: EventFn a a
170− event sink scheduler time value = sink.event time value
182+ event :: Sink a -> Scheduler -> EventFn a
183+ event (Sink sink) scheduler time value = sink.event time value
171184
172185-- Stream factories
173186just :: forall a. a -> Stream a
@@ -192,7 +205,7 @@ runFromArray :: forall a. Array a -> Sink a -> Scheduler -> Disposable
192205runFromArray arr sink scheduler = scheduleTasks tasks scheduler
193206 where
194207 tasks :: Array Task
195− tasks = snoc eventTasks (endTask sink)
208+ tasks = eventTasks <|> [ (endTask sink) ]
196209
197210 eventTasks :: Array Task
198211 eventTasks = map (flip eventTask sink) arr
@@ -201,39 +214,34 @@ periodic :: Number -> Stream Unit
201214periodic period = createStream (runPeriodic period)
202215
203216runPeriodic :: Number -> Sink Unit -> Scheduler -> Disposable
204−runPeriodic period sink scheduler = { dispose: scheduledTask.dispose }
217+runPeriodic period sink (Scheduler scheduler) = { dispose: scheduledTask.dispose }
205218 where
206− p = case scheduler of Scheduler a -> a.periodic
207− scheduledTask = p period (eventTask unit sink)
219+ scheduledTask = scheduler.periodic period (eventTask unit sink)
208220
209221-- combinators
210222_map :: forall a b. (a -> b) -> Stream a -> Stream b
211223_map f stream = createEventCombinator mapEvent stream
212224 where
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)
215226
216227filter :: forall a. (a -> Boolean) -> Stream a -> Stream a
217228filter predicate stream = createEventCombinator event stream
218229 where
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
221231 then sink.event time value
222232 else unit
223233
224234tapEvent :: forall e a. (a -> EffStream e Unit) -> Stream a -> Stream a
225235tapEvent f stream = createEventCombinator event stream
226236 where
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
229238 where -- find a better way to perform these side effects
230239 x = unsafePerformEff (f value)
231240
232241tapEnd :: forall e a. EffStream e Unit -> Stream a -> Stream a
233242tapEnd f stream = createEndCombinator end stream
234243 where
235− end :: EndFn a
236− end sink scheduler time = sink.end time
244+ end (Sink sink) (Scheduler scheduler) time = sink.end time
237245 where -- find a better way to perform these side effects
238246 x = unsafePerformEff f
239247
@@ -243,18 +251,51 @@ startWith value stream = concat (just value) stream
243251constant :: forall a b. b -> Stream a -> Stream b
244252constant value stream = createEventCombinator constantEvent stream
245253 where
246− constantEvent sink scheduler time x = sink.event time value
254+ constantEvent (Sink sink) (Scheduler scheduler) time x = sink.event time value
247255
248256scan :: forall a b. (b -> a -> b) -> b -> Stream a -> Stream b
249257scan f seed stream = startWith seed $ createEventCombinator scanEvent stream
250258 where
259+ state :: State b
251260 state = createState seed
252261
253262 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)
264+
265+skipRepeats :: forall a. (Eq a) => Stream a -> Stream a
266+skipRepeats = skipRepeatsWith eq
267+
268+sample :: forall a b c. (a -> b -> c) -> Stream a -> Stream b -> Stream c
269+sample f sampler stream = createStream $ runSample (createState Nothing)
270+ where
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
275+ ]
276+
277+createHoldSink :: forall a. State (Maybe a) -> Sink a
278+createHoldSink state = createSink event end
279+ where
280+ event time value = always unit (state.set \_ -> Just value)
281+ end time = unit
282+
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
285+ where
286+ end time = sink.end time
287+ event time value =
288+ if isJust (runPure state.get)
289+ then sink.event time $ f value (unsafePartial $ fromJust (runPure state.get))
290+ else unit
291+
292+always :: forall a b. a -> b -> a
293+always a b = a
255294
256295-- 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 }
297+
298+createState :: forall a. a -> State a
258299createState seed = { set, get }
259300 where
260301 ref :: Ref a
@@ -290,3 +331,7 @@ foreign import continueWith :: forall a. (Unit -> Stream a) -> Stream a -> Strea
290331foreign import concat :: forall a. Stream a -> Stream a -> Stream a
291332foreign import merge :: forall a. Array (Stream a) -> Stream a
292333foreign 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