-
Notifications
You must be signed in to change notification settings - Fork 5
/
lecture14.fsx
150 lines (112 loc) · 4.03 KB
/
lecture14.fsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// lecture 14
// duality, push/pull, IEnumerable/IObservable, rx (reactive extensions)
#r "FSharp.PowerPack.dll"
#I "/Users/james/repos/FSharp.Control.Reactive/bin"
#r "System.Reactive.Core.dll"
#r "System.Reactive.Interfaces.dll"
#r "System.Reactive.Linq.dll"
#r "System.Reactive.Providers.dll"
#r "System.Reactive.PlatformServices.dll"
#r "System.Reactive.Experimental.dll"
#r "FSharp.Control.Reactive.dll"
open System
open System.Reactive.Linq
open FSharp.Control.Reactive
open Builders
open System.Reactive.Linq
let obs1 = Observable.Return(42)
obs1.Subscribe(printfn "%d")
let enu1 = [ 1 ]
for i in enu1 do printfn "%d" i
let obs2 = Observable.Empty<int>()
obs2.Subscribe(printfn "%d")
let enu2 = []
for i in enu2 do printfn "%d" i
let obs3 = Observable.Never<int>()
obs3.Subscribe(printfn "%d")
// dual to stuck iterator
let obs4 = Observable.Throw<int>(new System.Exception("error"))
obs4.Subscribe(printfn "%d")
let obs5 = Observable.Range(0,3)
let enu5 = [ 0 .. 3 ]
let obs6 = Observable.Generate(
0,
(fun i -> i < 10),
(fun i -> i + 1),
(fun i -> i * i))
let sub1 = obs6.Subscribe(printfn "%d")
sub1.Dispose()
open System.IO
let fileWatcher = new FileSystemWatcher(@"/Users/james/test")
fileWatcher.EnableRaisingEvents <- true
// imperative style
fileWatcher.Created.Add(fun fse ->
if not (fse.Name.EndsWith("~")) then printfn "new file!) %s" fse.Name)
let isRealFile (fse:FileSystemEventArgs) = fse.Name.EndsWith("~") |> not
let formatCreatedEvent (fse:FileSystemEventArgs) = sprintf "new file! %s" fse.Name
let sub2 =
fileWatcher.Created
|> Observable.filter isRealFile
|> Observable.map formatCreatedEvent
|> Observable.subscribe(printfn "%s")
sub2.Dispose()
// fizzbuzz
let createTimerAndObservable timerInterval =
// setup a timer
let timer = new System.Timers.Timer(float timerInterval)
timer.AutoReset <- true
// events are automatically IObservable
let observable = timer.Elapsed
// return an async task
let task = async {
timer.Start()
do! Async.Sleep 5000
timer.Stop()
}
// return a async task and the observable
(task,observable)
type FizzBuzzEvent = {label:int; time: DateTime}
let areSimultaneous (earlierEvent,laterEvent) =
let {label=_;time=t1} = earlierEvent
let {label=_;time=t2} = laterEvent
t2.Subtract(t1).Milliseconds < 50
// create the event streams and raw observables
let timer3, timerEventStream3 = createTimerAndObservable 300
let timer5, timerEventStream5 = createTimerAndObservable 500
// convert the time events into FizzBuzz events with the appropriate id
let eventStream3 = timerEventStream3
|> Observable.map (fun _ -> {label=3; time=DateTime.Now})
let eventStream5 = timerEventStream5
|> Observable.map (fun _ -> {label=5; time=DateTime.Now})
// combine the two streams
let combinedStream =
Observable.merge eventStream3 eventStream5
// make pairs of events
let pairwiseStream =
combinedStream |> Observable.pairwise
// split the stream based on whether the pairs are simultaneous
let simultaneousStream, nonSimultaneousStream =
pairwiseStream |> Observable.partition areSimultaneous
// split the non-simultaneous stream based on the id
let fizzStream, buzzStream =
nonSimultaneousStream
// convert pair of events to the first event
|> Observable.map (fun (ev1,_) -> ev1)
// split on whether the event id is three
|> Observable.partition (fun {label=id} -> id=3)
//print events from the combinedStream
combinedStream
|> Observable.subscribe (fun {label=id;time=t} ->
printf "[%i] %i.%03i " id t.Second t.Millisecond)
//print events from the simultaneous stream
simultaneousStream
|> Observable.subscribe (fun _ -> printfn "FizzBuzz")
//print events from the nonSimultaneous streams
fizzStream
|> Observable.subscribe (fun _ -> printfn "Fizz")
buzzStream
|> Observable.subscribe (fun _ -> printfn "Buzz")
// run the two timers at the same time
[timer3;timer5]
|> Async.Parallel
|> Async.RunSynchronously