Reputation: 377
I am learning RX, and trying to port some code in C# to F#. The following is C# example for using a timer:
Console.WriteLine("Current Time: " + DateTime.Now);
var source = Observable.Timer(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1)).Timestamp();
using (source.Subscribe(x => Console.WriteLine("{0}: {1}", x.Value, x.Timestamp)))
{
Console.WriteLine("Press any key to unsubscribe");
Console.ReadKey();
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
The following is my code trying to do the same:
#light
open System
open System.Collections.Generic
open System.Linq
open System.Reactive
open System.Reactive.Linq
open System.Reactive.Subjects
printfn "Current Time: %A" DateTime.Now
let source = Observable.Timer(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(1.0)).Timestamp()
source.Subscribe(fun x -> printfn "%A %A" x.Value x.Timestamp) |> ignore
But I got compiler errors:
Error 1 Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
I don't know how what type is for x.Value
and x.Timestamp
.
By the way, I also don't know how to re-write using in C# here in F#.
Please show me the correct code for this.
Upvotes: 3
Views: 642
Reputation: 10350
Below is a "direct translation" into F# from C#:
open System
open System.Reactive
open System.Reactive.Linq
printfn "Current Time: %A" DateTime.Now
let source = Observable.Timer(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds (1.0)).Timestamp()
using (source.Subscribe(fun (x:Timestamped<int64>) -> printfn "%A %A" x.Value x.Timestamp))
(fun _ ->
printfn "Press any key to unsubscribe"
Console.ReadKey() |> ignore
)
printfn "Press any key to stop"
Console.ReadKey() |> ignore
When running allow it to pass 5 seconds prior to seeing how 1 sec Timer events begin flowing in.
ADDENDUM: Type of input argument in the lambda expression that, in turn, is the argument of Iobservable.Subscribe()
is the type of values of IObservable
that we call Subscribe()
on, i.e the type of values constituing IObservable
source
.
In turn, source
represents result of Observable.Timer(DateTimeOffset, TimeSpan)
method that returns an observable sequence that produces a value at due time and then after each period. This sequence has type IObservable<int64>
.
Timestamp()
method, when being applied to IObservable<int64>
yields IObservable<Timestamped<int64>>
.
So, eventually our source
is IObservable
of type Timestamped<int64>
, which the code snippet above reflects as explicit type of argument x
of the anonymous function within Subscribe()
.
Upvotes: 2
Reputation: 13862
Subscribe isn't working because it's overloaded. If you specify which overload to use then it works.
(source.Subscribe : (Timestamped<int64> -> unit) -> IDisposable)(fun x -> printfn "%A %A" x.Value x.Timestamp) |> ignore
If you use the Add method instead of Subscribe, then the type will resolve correctly.
printfn "Current Time: %A" DateTime.Now
let source = Observable.Timer(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(1.0)).Timestamp()
source.Add(fun x -> printfn "%A %A" x.Value x.Timestamp)
printfn "Press any key to stop"
Console.ReadKey() |> ignore
Upvotes: 1