Skip to content

Instantly share code, notes, and snippets.

@andybrackley
Created February 23, 2014 19:32
Show Gist options
  • Save andybrackley/9176100 to your computer and use it in GitHub Desktop.
Save andybrackley/9176100 to your computer and use it in GitHub Desktop.
type [<Measure>] seconds
type Interval = { Name: string; Duration: int<seconds>; Elapsed : int<seconds> }
type Interval with
member x.Remaining = x.Duration - x.Elapsed
type Workout = { Name: string; Intervals : Interval list }
type Workout with
member x.WorkoutTime = x.Intervals |> Seq.sumBy (fun x -> x.Duration)
type WorkoutPreferences = { Countdown : int<seconds>; WarningPeriod : int<seconds> }
let interval1 = { Name = "Work"; Duration = 20<seconds>; Elapsed = 0<seconds> }
let interval2 = { Name = "Rest"; Duration = 10<seconds>; Elapsed = 0<seconds> }
let workout =
{
Name = "Tabata";
Intervals = seq { for i in 1 .. 8 do yield [ interval1; interval2 ] } |> Seq.concat |> Seq.toList
}
let generateSequenceFromInterval interval =
seq { for i in 1 .. (int)interval.Duration do yield { interval with Elapsed = i * 1<seconds> } }
let flattenedWorkout workout =
workout.Intervals
|> Seq.collect generateSequenceFromInterval
|> Seq.map (fun x -> (workout, x))
open System
open System.Reactive.Linq
open FSharp.Reactive
/// Extensions/Improvements to the FSharp.Reactive library
module Observable =
/// Merges two observable sequences into one observable sequence
/// This version overrides the one in the lib which expects both IObservables to be the same type
let zip (second: IObservable<'T>) (first: IObservable<'U>) =
let inner a b = a, b
Observable.Zip(first, second, Func<_,_,_> inner)
[<EntryPoint>]
let main args =
let ivals = generateSequenceFromInterval interval1
let wkt = (flattenedWorkout workout |> Seq.toList)
let obsWkt = wkt |> Observable.toObservable
let isPaused = ref false
let pace =
Observable.Interval(TimeSpan.FromSeconds(1.0))
.Where(Func<_,_>(fun _ -> !isPaused = false))
let obs = obsWkt |> Observable.zip pace |> Observable.map( fun (a, b) -> a)
let sub = obs.Subscribe(fun (wkt, ival) -> printfn "Workout: %s, Interval: %s, Elapsed: %A, Remain: %A" wkt.Name ival.Name ival.Elapsed ival.Remaining )
// Create a skipped interval set
sub.Dispose()
let obs2 = obsWkt |> Observable.skip 10 |> Observable.zip pace |> Observable.map( fun (a,b) -> a)
let sub2 = obs2.Subscribe(fun (wkt, ival) -> printfn "Sub2 Workout: %s, Interval: %s, Elapsed: %A, Remain: %A" wkt.Name ival.Name ival.Elapsed ival.Remaining )
System.Threading.Thread.Sleep((int)(TimeSpan.FromMinutes(4.0).TotalMilliseconds))
0
(*
(* SAMPLES *)
(* Manually Iterate a Sequence *)
let sequence = seq { 1 .. 10 }
let enm = sequence.GetEnumerator()
while enm.MoveNext() do
printfn "%A" enm.Current
*)
@andybrackley
Copy link
Author

Another alternative:

type IntervalState =
| Running of int
| Complete

type SetState =
| Running of int * IntervalState
| Complete

let runInterval time = seq {
for i in time .. -1 .. 0 do
yield IntervalState.Running(i)

yield IntervalState.Complete
}

let runSet repeats = seq {
for set in 0 .. repeats do
yield! runInterval 10 |> Seq.map(fun i -> SetState.Running(set, i))
yield SetState.Complete
}

module Seq =
let exec func collection =
collection |> Seq.map(fun x -> func x; x )

let getText = function
| SetState.Running(set, intervalState)
-> match intervalState with
| IntervalState.Running(time) -> sprintf "Set: %d, Remain: %d" set time
| IntervalState.Complete -> sprintf "Set: %d - Interval Complete" set
| SetState.Complete -> sprintf "Set Complete"

runSet 2
|> Seq.map(getText)
|> Seq.exec(fun _ -> async { do! Async.Sleep(1000) } |> Async.RunSynchronously )
|> Seq.iter(fun out -> printfn "%s" out)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment