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
Throttlethere 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 about
if conditionalon 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 throttleDurationand perhaps construct the
throttleFactoryin some slick way by parsing the Console.ReadLine and in case it's double, parse piping/creating an infinite sequence or something from
Console.ReadLine()and feeding the values directly into the
Throttlefunction (or to
throttleFactory). 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.
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