I'm basically redoing a piece of reactive C# code posted in SO code in F#, please, see below. The translation is fairly literal, I've just written the infinite loop as a recursive function and rearranged the conditions for breaking the recursion. Any notes regarding style and so forth, even the most subjective ones, are a fair game, but I would like to present two explicit questions:
As reading svick's comment I realised I'm actually asking advice on how could I refactor the throttleDuration
part of code to be actually be inside the throttleFactory
, which in turn then would produce the desired doubles. It looks like I'm feeling the effect of trying to think more functionally and in terms of function composition as it feels more natural than in F# than in C#.
In any event, two points of note here:
- Would this refactoring question be a better fit for Stackoverflow question?
- Currently in my intended sequence of doubles from
throttleFactory
toThrottle
there is an added twist in form of the q for quitting variable. I believe this could be safely ignored and just assume there would be only valid doubles produced somehow by some kind of a generator. This would also drop out the question aboutif conditional
on context my particular piece of code (of course, not in general sense) unless there's some slick way of doing the generating and checking with active patterns or something.
As writing this now, it also looks like I wouldn't need the whole inputLoop
variable in case I'd use just some arbitrary generator, which in turn negates some the ideas I had with regarding rehearsing this (I haven't tried to write actual code as of yet). The thing is, I'm rookie enough with this so as not to know if going this "plain generator or q for quitting also" route would bear fruit and I'm afraid I run out of time trying if I try for too long by myself.
The above mentioned sequence generation (excluding the issue of quitting) is the vague reason I'm suspiciously eying at the ref cell
. I leave the rest of my original post as is for reference.
Ignoring the magic numbers, would there be a more idiomatic (or cleaner) way to write the generator or equivalent function?
open System
open FSharp.Reactive
open System.Reactive
open System.Reactive.Linq
[<EntryPoint>]
let main argv =
let throttleValueGenerator(minInclusiveMillisecondsLowerBound, maxExlusivemillisecondsUpperBound, countOfValues) =
let rnd = new System.Random()
Observable.Generate(0, (fun value -> value < countOfValues), (fun value -> value + 1), (fun value -> rnd.Next(minInclusiveMillisecondsLowerBound, maxExlusivemillisecondsUpperBound)), (fun value -> TimeSpan.FromSeconds(float 1)))
//The idea here is to produce events on one second intervals and whenever throttle is more than one second, no value will be output.
let throttleFactory = fun _ -> throttleValueGenerator(100, 2000, 30)
let sequence = Observable.Interval(TimeSpan.FromSeconds(1.0)).Throttle(throttleFactory)
printfn "Sequence starts on %A..." DateTime.Now
let subscription = sequence.Subscribe(fun a -> printfn "%i on %A" a DateTime.Now)
Console.ReadKey() |> ignore
printfn "Sequence end on %A." DateTime.Now
subscription.Dispose()
0
I became to think if it'd be possible to leave out the intermediary feeling
ref throttleDuration
and perhaps construct thethrottleFactory
in some slick way by parsing the Console.ReadLine and in case it's double, parse piping/creating an infinite sequence or something fromConsole.ReadLine()
and feeding the values directly into theThrottle
function (or tothrottleFactory
). There mightn't be, but I would like to avoid banging my head too hard when thinking of that, albeit it might be educational.Do those if conditionals look all right from functional style perspective or could active patterns fit here? I read about them in F# for Fun and profit article by Scott Wlaschin (a good site, slick looking code) and they could be usable in situations like this at least in larger code bases.
For the code below, I installed both Rx-Main and FSharp.Reactive.
open System
open FSharp.Reactive
open System.Reactive
open System.Reactive.Linq
[<EntryPoint>]
let main argv =
let throttleDuration = ref (TimeSpan.FromSeconds(0.5));
let throttleFactory = fun _ -> Observable.Timer(!throttleDuration)
let sequence = Observable.Interval(TimeSpan.FromSeconds(1.0)).Throttle(throttleFactory);
let subscription = sequence.Subscribe(fun a -> printfn "%i" a)
let rec inputLoop() =
printfn "Enter throttle duration in seconds or 'q' to quit"
let input = Console.ReadLine().Trim()
if not(String.Equals(input, "q", StringComparison.InvariantCultureIgnoreCase)) then
let success, value = System.Double.TryParse input
if success then
throttleDuration := TimeSpan.FromSeconds(value);
inputLoop()
inputLoop() |> ignore
subscription.Dispose()
0
throttleDuration
to mutate, but not be mutable? That doesn't make much sense to me. \$\endgroup\$