/// m08 stream: an event stream as a pure automaton (a Mealy machine). /// A step feeds one event and returns the (possibly empty) list of outputs it produced and the stream to use for /// the next event. Nothing is mutated, so a stream value can be run any number of times with the same results. module Snake.Stream /// Something that happens to the program: time passing (ms since start) or a key going down or up, and from /// Module 13 a mouse click at `(x, y)` in canvas pixels. Every stream ignores the kinds of event it does not use. type Event = | Time of int64 | KeyDown of string | KeyUp of string | Click of int * int type Stream<'a> = Stream of (Event -> 'a list * Stream<'a>) /// Feed one event to `s`: the outputs it produced and the stream for the next event. let step (e: Event) (s: Stream<'a>) : 'a list * Stream<'a> = failwith "TODO m08" /// Emits the `key` of every KeyDown event; ignores everything else. /// (The stub is wrapped in `Stream` so the TODO only fires when the stream is stepped.) let keyDowns: Stream = Stream(fun _ -> failwith "TODO m08") /// Emits the `key` of every KeyUp event; ignores everything else. let keyUps: Stream = Stream(fun _ -> failwith "TODO m08") /// (m13) Emits the position `(x, y)` of every Click event; ignores everything else. /// Given: nothing to write here. It is the third source, built exactly like your `keyDowns`. let clicks: Stream = let rec source () = Stream(fun e -> match e with | Click(x, y) -> [ (x, y) ], source () | _ -> [], source ()) source () /// On `Time t`, emits every multiple `k*ms` with `last < k*ms <= t`, ascending, where `last` starts at 0 /// and becomes `t` afterwards. A big time jump can emit several values. Ignores key events. /// Hint: write a private helper that carries `last`. let interval (ms: int64) : Stream = failwith "TODO m08" /// Apply `f` to every output. let map (f: 'a -> 'b) (s: Stream<'a>) : Stream<'b> = failwith "TODO m08" /// Keep only the outputs for which `p` is true. let filter (p: 'a -> bool) (s: Stream<'a>) : Stream<'a> = failwith "TODO m08" /// Apply `f` to every output; `Some b` emits `b`, `None` is dropped (like `List.choose`). let choose (f: 'a -> 'b option) (s: Stream<'a>) : Stream<'b> = failwith "TODO m08" /// Both streams step on every event; the outputs of `a` come before the outputs of `b`. let merge (a: Stream<'a>) (b: Stream<'a>) : Stream<'a> = failwith "TODO m08" /// Fold the outputs into an accumulator, starting from `z`; emits each new accumulator (not `z` itself). let scan (f: 'b -> 'a -> 'b) (z: 'b) (s: Stream<'a>) : Stream<'b> = failwith "TODO m08" /// Emit `v` once, before the outputs of the first step; later steps are unaffected. /// Note: streams only act when an event arrives, so if no event ever arrives, `v` is never emitted. let startWith (v: 'a) (s: Stream<'a>) : Stream<'a> = failwith "TODO m08" /// (m10) Limit how far one Time event can move the clock that `s` sees, so a long silence (a background tab) /// does not turn into hundreds of beats at once. /// `s` gets a clock of its own, starting at 0. On `Time t` that clock advances by `t - last`, but by at most `maxGap` /// and never by less than 0 (time does not run backwards), where `last` is the `t` of the previous Time event /// (0 at the start). `s` is then stepped with `Time clock`. Key and click events are passed to `s` unchanged. /// Hint: a private helper that carries `last` and `clock`, like the one for `interval`. let clampTime (maxGap: int64) (s: Stream<'a>) : Stream<'a> = failwith "TODO m10" /// Feed all events through the stream and collect every output, in order. A pure fold. let run (events: Event list) (s: Stream<'a>) : 'a list = failwith "TODO m08"