2 people like it.

Observable.computed

Knockout (http://knockoutjs.com) provides observable primitives similar to IObservable in Rx. Knockout also has ko.computed, which abstracts away individual subscriptions: you write a function that references the current values of observables, and it takes care of the rest. Here is ko.computed in F#.

  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
142: 
143: 
144: 
145: 
146: 
147: 
148: 
149: 
150: 
151: 
152: 
153: 
154: 
155: 
156: 
157: 
158: 
159: 
160: 
161: 
162: 
163: 
164: 
165: 
166: 
167: 
168: 
169: 
170: 
171: 
172: 
173: 
174: 
175: 
176: 
177: 
178: 
179: 
180: 
181: 
182: 
183: 
184: 
185: 
186: 
187: 
188: 
189: 
190: 
191: 
192: 
193: 
194: 
195: 
196: 
197: 
198: 
199: 
200: 
201: 
202: 
203: 
204: 
205: 
206: 
207: 
208: 
209: 
210: 
211: 
212: 
213: 
214: 
215: 
216: 
217: 
218: 
219: 
220: 
221: 
222: 
223: 
224: 
225: 
226: 
227: 
228: 
229: 
230: 
231: 
232: 
233: 
234: 
235: 
236: 
237: 
238: 
239: 
240: 
241: 
242: 
243: 
244: 
245: 
246: 
247: 
248: 
249: 
250: 
251: 
252: 
253: 
254: 
255: 
256: 
257: 
258: 
259: 
open System
open System.Collections.Concurrent
open System.Collections.Generic
open System.Reflection
open System.Threading

/// There is no common superclass of all IObservable<T>.
type IObservable = obj

/// Raised when an observable has not yet published a value.
type DeferredValueException() =
    inherit Exception()

/// Raised when an observable's value is accessed after the observable publishes an error.
type ObservableException(message : string, innerException : Exception) =
    inherit Exception(message, innerException)

/// The last value of an observable, or an error, or neither.
type IObservableValue<'a> =
    abstract HasValue : bool
    abstract Value : 'a
    abstract Exception : Exception

/// Implementation of IObservable<T> and IObservableValue<T>.
type Observable<'a>() =
    let syncRoot = obj()
    let mutable subs : IObserver<'a> list = [ ]
    let mutable lastValue : Choice<Exception, 'a> option = None

    let rec removeFirst value =
        function
        | x :: xs when x = value -> xs
        | _ :: xs -> removeFirst value xs
        | [ ] -> [ ]

    member t.Publish(value) =
        let subs =
            lock syncRoot <| fun () ->
                lastValue <- Some (Choice2Of2 value)
                subs

        for sub in subs do sub.OnNext(value)

    member t.PublishError(ex) =
        let subs =
            lock syncRoot <| fun () ->
                lastValue <- Some (Choice1Of2 ex)
                subs

        for sub in subs do sub.OnError(ex)

    interface IObservable<'a> with
        member t.Subscribe(sub) =
            lock syncRoot <| fun () ->
                subs <- sub :: subs

            { new IDisposable with
                member x.Dispose() =
                    lock syncRoot <| fun () ->
                        subs <- removeFirst sub subs
            }

    interface IObservableValue<'a> with
        member t.HasValue = Option.isSome lastValue

        member t.Value =
            match lastValue with
            | Some (Choice1Of2 ex) -> raise (ObservableException(ex.Message, ex))
            | Some (Choice2Of2 value) -> value
            | None -> Unchecked.defaultof<_>

        member t.Exception =
            match lastValue with
            | Some (Choice1Of2 ex) -> ex
            | _ -> null

/// Implementation of IObserver<T>, in terms of a pair of F# functions.
type Observer<'a>(next : 'a -> unit, error : Exception -> unit) =
    interface IObserver<'a> with
        member t.OnNext(value) =
            next value
            
        member t.OnError(ex) =
            error ex
            
        member t.OnCompleted() =
            ()

module private Impl =

    type Type with
        member t.CheckedGetMethod(name : string, bindingFlags : BindingFlags) =
            match t.GetMethod(name, bindingFlags) with
            | null -> failwithf "No method '%s' on %O" name t
            | mi -> mi

    let memoize (fn : 'a -> 'b) : 'a -> 'b =
        let dict = Dictionary()
        fun a ->
            let found, b = lock dict <| fun () -> dict.TryGetValue(a)
            if found then
                b
            else
                let b = fn a
                lock dict <| fun () -> dict.[a] <- b
                b

    type IInvoker =
        abstract Invoke<'a> : unit -> obj

    /// There is no common superclass of all IObservable<T>. Therefore if we have an observable,
    /// and we don't know what 'T' is, we have to use reflection to call the Subscribe method.
    let subscribeAny : Type -> (IObservable * (obj -> unit) * (Exception -> unit)) -> IDisposable =
        let md = typeof<IInvoker>.CheckedGetMethod("Invoke", BindingFlags.Public ||| BindingFlags.Instance)
        memoize <| fun typ ->
            let picker (iface : Type) =
                if iface.IsGenericType && iface.GetGenericTypeDefinition() = typedefof<IObservable<_>> then
                    Some (iface.GetGenericArguments().[0])
                else
                    None

            let valueType =
                match Array.tryPick picker (typ.GetInterfaces()) with
                | Some typ -> typ
                | None -> failwithf "%O does not implement IObservable<T>" typ

            let mi = md.MakeGenericMethod([| valueType |])

            fun (obs, next, error) ->
                let invoker =
                    { new IInvoker with
                        member t.Invoke<'a>() =
                            (obs :?> IObservable<'a>).Subscribe(Observer(next, error)) :> _
                    }

                unbox (mi.Invoke(invoker, [| |]))

module Observable =

    [<AbstractClass>]
    type internal Monitor() =
        [<ThreadStatic; DefaultValue>]
        static val mutable private current : Monitor option

        static member Current : Monitor =
            match Monitor.current with
            | Some m -> m
            | None -> failwithf "Not inside Observable.Computed"
            
        static member SetCurrent(m : Monitor) : IDisposable =
            let oldCurrent = Monitor.current
            Monitor.current <- Some m
            { new IDisposable with member t.Dispose() = Monitor.current <- oldCurrent }

        abstract GetValue<'a> : obs : IObservable<'a> -> 'a

    let computed<'a> (fn : unit -> 'a) : Observable<'a> =
        let values = ConcurrentDictionary<IObservable, Choice<Exception, obj>>()
        let syncRoot = obj()
        let subs = Dictionary<IObservable, IDisposable>()
        let observable = Observable<'a>()

        // Call the function and, using the Monitor class, track the observables that it accesses.
        //  Subscribe to any new ones, and unsubscribe from any stale ones. Halt evaluation if the
        //  function accesses an observable for which we haven't seen a value (but still keep our
        //  subscriptions, so we get notified when a value does eventually arrive).
        // Our IObservableValue<T> interface reduces the need to throw a DeferredValueException,
        //  by letting us access the last published value without having a subscription.
        let rec refresh () =
            let obses = HashSet<IObservable>()
            let m =
                { new Monitor() with
                    member t.GetValue<'b>(obs) =
                        let obs = obs :> IObservable
                        ignore (obses.Add(obs))

                        match obs with
                        | :? IObservableValue<'b> as lv ->
                            if lv.HasValue then
                                lv.Value
                            else
                                raise (DeferredValueException())

                        | _ ->
                            match values.TryGetValue(obs) with
                            | true, Choice1Of2 ex -> raise (ObservableException(ex.Message, ex))
                            | true, Choice2Of2 value -> unbox value
                            | false, _ -> raise (DeferredValueException())
                }

            let value =
                using (Monitor.SetCurrent(m)) <| fun _ ->
                    try
                        Some (Choice2Of2 (fn ()))
                    with
                    | :? DeferredValueException -> None
                    | :? ObservableException as ex -> Some (Choice1Of2 ex.InnerException)
                    | ex -> Some (Choice1Of2 ex)

            lock syncRoot <| fun () ->
                for pair in Array.ofSeq subs do
                    if not (obses.Contains(pair.Key)) then
                        pair.Value.Dispose()
                        ignore (subs.Remove(pair.Key))

                for obs in obses do
                    if not (subs.ContainsKey(obs)) then
                        let on value =
                            values.[obs] <- value
                            refresh ()

                        subs.[obs] <- Impl.subscribeAny (obs.GetType()) (obs, Choice2Of2 >> on, Choice1Of2 >> on)

            match value with
            | Some (Choice1Of2 ex) -> observable.PublishError(ex)
            | Some (Choice2Of2 value) -> observable.Publish(value)
            | None -> ()

        refresh ()
        observable
        

[<AutoOpen>]
module ObservableExtensions =

    type IObservable<'a> with
        member t.Value : 'a =
            // The key to making the whole thing work. (If we bypass this extension property,
            //  and access the observable's last value directly, we don't get chance to
            //  subscribe to the observable.)
            Observable.Monitor.Current.GetValue(t)

        member t.Subscribe(next : 'a -> unit, error : Exception -> unit) : IDisposable =
            // A helper method for the demo below. F# provides Subscribe('a -> unit),
            //  but we want to handle errors too.
            t.Subscribe(Observer(next, error))

[<EntryPoint>]
let main args =
    let obs1 = Observable()
    use d1 = obs1.Subscribe(printfn "Got obs1: %d", fun ex -> printfn "Error obs1: %s" ex.Message)
    let obs2 = Observable()
    use d2 = obs2.Subscribe (printfn "Got obs2: %d", fun ex -> printfn "Error obs2: %s" ex.Message)
    let c =
        Observable.computed <| fun () ->
            if obs2.Value < 10 then
                failwithf "%d is too low" obs2.Value
            else
                obs1.Value + obs2.Value

    use dc = c.Subscribe (printfn "Got computed: %d", fun ex -> printfn "Error computed: %s" ex.Message)
    obs1.Publish(10)

    let r = Random()
    while true do
        obs2.Publish(r.Next(0, 20))
        Thread.Sleep(1000)

    0
namespace System
namespace System.Collections
namespace System.Collections.Concurrent
namespace System.Collections.Generic
namespace System.Reflection
namespace System.Threading
Multiple items
type IObservable = obj

Full name: Script.IObservable


 There is no common superclass of all IObservable<T>.


--------------------
type IObservable<'T> =
  member Subscribe : observer:IObserver<'T> -> IDisposable

Full name: System.IObservable<_>
type obj = Object

Full name: Microsoft.FSharp.Core.obj
Multiple items
type DeferredValueException =
  inherit Exception
  new : unit -> DeferredValueException

Full name: Script.DeferredValueException


 Raised when an observable has not yet published a value.


--------------------
new : unit -> DeferredValueException
Multiple items
type Exception =
  new : unit -> Exception + 2 overloads
  member Data : IDictionary
  member GetBaseException : unit -> Exception
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member GetType : unit -> Type
  member HelpLink : string with get, set
  member InnerException : Exception
  member Message : string
  member Source : string with get, set
  member StackTrace : string
  ...

Full name: System.Exception

--------------------
Exception() : unit
Exception(message: string) : unit
Exception(message: string, innerException: exn) : unit
Exception(info: Runtime.Serialization.SerializationInfo, context: Runtime.Serialization.StreamingContext) : unit
Multiple items
type ObservableException =
  inherit Exception
  new : message:string * innerException:Exception -> ObservableException

Full name: Script.ObservableException


 Raised when an observable's value is accessed after the observable publishes an error.


--------------------
new : message:string * innerException:Exception -> ObservableException
val message : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
val innerException : Exception
type IObservableValue<'a> =
  interface
    abstract member Exception : Exception
    abstract member HasValue : bool
    abstract member Value : 'a
  end

Full name: Script.IObservableValue<_>


 The last value of an observable, or an error, or neither.
abstract member IObservableValue.HasValue : bool

Full name: Script.IObservableValue`1.HasValue
type bool = Boolean

Full name: Microsoft.FSharp.Core.bool
abstract member IObservableValue.Value : 'a

Full name: Script.IObservableValue`1.Value
Multiple items
abstract member IObservableValue.Exception : Exception

Full name: Script.IObservableValue`1.Exception

--------------------
type Exception =
  new : unit -> Exception + 2 overloads
  member Data : IDictionary
  member GetBaseException : unit -> Exception
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member GetType : unit -> Type
  member HelpLink : string with get, set
  member InnerException : Exception
  member Message : string
  member Source : string with get, set
  member StackTrace : string
  ...

Full name: System.Exception

--------------------
Exception() : unit
Exception(message: string) : unit
Exception(message: string, innerException: exn) : unit
Multiple items
module Observable

from Microsoft.FSharp.Control

--------------------
type Observable<'a> =
  interface IObservableValue<'a>
  interface IObservable<'a>
  new : unit -> Observable<'a>
  member Publish : value:'a -> unit
  member PublishError : ex:Exception -> unit

Full name: Script.Observable<_>


 Implementation of IObservable<T> and IObservableValue<T>.


--------------------
new : unit -> Observable<'a>
val syncRoot : Object
val mutable subs : IObserver<'a> list
type IObserver<'T> =
  member OnCompleted : unit -> unit
  member OnError : error:Exception -> unit
  member OnNext : value:'T -> unit

Full name: System.IObserver<_>
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val mutable lastValue : Choice<Exception,'a> option
Multiple items
type Choice<'T1,'T2> =
  | Choice1Of2 of 'T1
  | Choice2Of2 of 'T2

Full name: Microsoft.FSharp.Core.Choice<_,_>

--------------------
type Choice<'T1,'T2,'T3> =
  | Choice1Of3 of 'T1
  | Choice2Of3 of 'T2
  | Choice3Of3 of 'T3

Full name: Microsoft.FSharp.Core.Choice<_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4> =
  | Choice1Of4 of 'T1
  | Choice2Of4 of 'T2
  | Choice3Of4 of 'T3
  | Choice4Of4 of 'T4

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5> =
  | Choice1Of5 of 'T1
  | Choice2Of5 of 'T2
  | Choice3Of5 of 'T3
  | Choice4Of5 of 'T4
  | Choice5Of5 of 'T5

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6> =
  | Choice1Of6 of 'T1
  | Choice2Of6 of 'T2
  | Choice3Of6 of 'T3
  | Choice4Of6 of 'T4
  | Choice5Of6 of 'T5
  | Choice6Of6 of 'T6

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6,'T7> =
  | Choice1Of7 of 'T1
  | Choice2Of7 of 'T2
  | Choice3Of7 of 'T3
  | Choice4Of7 of 'T4
  | Choice5Of7 of 'T5
  | Choice6Of7 of 'T6
  | Choice7Of7 of 'T7

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_,_>
Multiple items
type Exception =
  new : unit -> Exception + 2 overloads
  member Data : IDictionary
  member GetBaseException : unit -> Exception
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member GetType : unit -> Type
  member HelpLink : string with get, set
  member InnerException : Exception
  member Message : string
  member Source : string with get, set
  member StackTrace : string
  ...

Full name: System.Exception

--------------------
Exception() : unit
Exception(message: string) : unit
Exception(message: string, innerException: exn) : unit
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
union case Option.None: Option<'T>
val removeFirst : ('b -> 'b list -> 'b list) (requires equality)
val value : 'b (requires equality)
val x : 'b (requires equality)
val xs : 'b list (requires equality)
val t : Observable<'a>
member Observable.Publish : value:'a -> unit

Full name: Script.Observable`1.Publish
val value : 'a
val subs : IObserver<'a> list
val lock : lockObject:'Lock -> action:(unit -> 'T) -> 'T (requires reference type)

Full name: Microsoft.FSharp.Core.Operators.lock
union case Option.Some: Value: 'T -> Option<'T>
union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>
val sub : IObserver<'a>
IObserver.OnNext(value: 'a) : unit
member Observable.PublishError : ex:Exception -> unit

Full name: Script.Observable`1.PublishError
val ex : Exception
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
IObserver.OnError(error: exn) : unit
override Observable.Subscribe : sub:IObserver<'a> -> IDisposable

Full name: Script.Observable`1.Subscribe
type IDisposable =
  member Dispose : unit -> unit

Full name: System.IDisposable
val x : IDisposable
IDisposable.Dispose() : unit
override Observable.HasValue : bool

Full name: Script.Observable`1.HasValue
module Option

from Microsoft.FSharp.Core
val isSome : option:'T option -> bool

Full name: Microsoft.FSharp.Core.Option.isSome
override Observable.Value : 'a

Full name: Script.Observable`1.Value
val raise : exn:Exception -> 'T

Full name: Microsoft.FSharp.Core.Operators.raise
property Exception.Message: string
module Unchecked

from Microsoft.FSharp.Core.Operators
val defaultof<'T> : 'T

Full name: Microsoft.FSharp.Core.Operators.Unchecked.defaultof
Multiple items
override Observable.Exception : Exception

Full name: Script.Observable`1.Exception

--------------------
type Exception =
  new : unit -> Exception + 2 overloads
  member Data : IDictionary
  member GetBaseException : unit -> Exception
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member GetType : unit -> Type
  member HelpLink : string with get, set
  member InnerException : Exception
  member Message : string
  member Source : string with get, set
  member StackTrace : string
  ...

Full name: System.Exception

--------------------
Exception() : unit
Exception(message: string) : unit
Exception(message: string, innerException: exn) : unit
Multiple items
type Observer<'a> =
  interface IObserver<'a>
  new : next:('a -> unit) * error:(Exception -> unit) -> Observer<'a>

Full name: Script.Observer<_>


 Implementation of IObserver<T>, in terms of a pair of F# functions.


--------------------
new : next:('a -> unit) * error:(Exception -> unit) -> Observer<'a>
val next : ('a -> unit)
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
val error : (Exception -> unit)
val t : Observer<'a>
override Observer.OnNext : value:'a -> unit

Full name: Script.Observer`1.OnNext
override Observer.OnError : ex:exn -> unit

Full name: Script.Observer`1.OnError
val ex : exn
override Observer.OnCompleted : unit -> unit

Full name: Script.Observer`1.OnCompleted
type Type =
  inherit MemberInfo
  member Assembly : Assembly
  member AssemblyQualifiedName : string
  member Attributes : TypeAttributes
  member BaseType : Type
  member ContainsGenericParameters : bool
  member DeclaringMethod : MethodBase
  member DeclaringType : Type
  member Equals : o:obj -> bool + 1 overload
  member FindInterfaces : filter:TypeFilter * filterCriteria:obj -> Type[]
  member FindMembers : memberType:MemberTypes * bindingAttr:BindingFlags * filter:MemberFilter * filterCriteria:obj -> MemberInfo[]
  ...

Full name: System.Type
val t : Type
member private Type.CheckedGetMethod : name:string * bindingFlags:BindingFlags -> MethodInfo

Full name: Script.Impl.CheckedGetMethod
val name : string
val bindingFlags : BindingFlags
type BindingFlags =
  | Default = 0
  | IgnoreCase = 1
  | DeclaredOnly = 2
  | Instance = 4
  | Static = 8
  | Public = 16
  | NonPublic = 32
  | FlattenHierarchy = 64
  | InvokeMethod = 256
  | CreateInstance = 512
  ...

Full name: System.Reflection.BindingFlags
Type.GetMethod(name: string) : MethodInfo
Type.GetMethod(name: string, bindingAttr: BindingFlags) : MethodInfo
Type.GetMethod(name: string, types: Type []) : MethodInfo
Type.GetMethod(name: string, types: Type [], modifiers: ParameterModifier []) : MethodInfo
Type.GetMethod(name: string, bindingAttr: BindingFlags, binder: Binder, types: Type [], modifiers: ParameterModifier []) : MethodInfo
Type.GetMethod(name: string, bindingAttr: BindingFlags, binder: Binder, callConvention: CallingConventions, types: Type [], modifiers: ParameterModifier []) : MethodInfo
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
val mi : MethodInfo
val private memoize : fn:('a -> 'b) -> ('a -> 'b) (requires equality)

Full name: Script.Impl.memoize
val fn : ('a -> 'b) (requires equality)
val dict : Dictionary<'a,'b> (requires equality)
Multiple items
type Dictionary<'TKey,'TValue> =
  new : unit -> Dictionary<'TKey, 'TValue> + 5 overloads
  member Add : key:'TKey * value:'TValue -> unit
  member Clear : unit -> unit
  member Comparer : IEqualityComparer<'TKey>
  member ContainsKey : key:'TKey -> bool
  member ContainsValue : value:'TValue -> bool
  member Count : int
  member GetEnumerator : unit -> Enumerator<'TKey, 'TValue>
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member Item : 'TKey -> 'TValue with get, set
  ...
  nested type Enumerator
  nested type KeyCollection
  nested type ValueCollection

Full name: System.Collections.Generic.Dictionary<_,_>

--------------------
Dictionary() : unit
Dictionary(capacity: int) : unit
Dictionary(comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>) : unit
Dictionary(capacity: int, comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>, comparer: IEqualityComparer<'TKey>) : unit
val a : 'a (requires equality)
val found : bool
val b : 'b
Dictionary.TryGetValue(key: 'a, value: byref<'b>) : bool
type private IInvoker =
  interface
    abstract member Invoke : unit -> obj
  end

Full name: Script.Impl.IInvoker
abstract member private IInvoker.Invoke : unit -> obj

Full name: Script.Impl.IInvoker.Invoke
val private subscribeAny : (Type -> IObservable * (obj -> unit) * (Exception -> unit) -> IDisposable)

Full name: Script.Impl.subscribeAny


 There is no common superclass of all IObservable<T>. Therefore if we have an observable,
 and we don't know what 'T' is, we have to use reflection to call the Subscribe method.
val md : MethodInfo
val typeof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typeof
field BindingFlags.Public = 16
field BindingFlags.Instance = 4
val typ : Type
val picker : (Type -> Type option)
val iface : Type
property Type.IsGenericType: bool
Type.GetGenericTypeDefinition() : Type
val typedefof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typedefof
Type.GetGenericArguments() : Type []
val valueType : Type
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val tryPick : chooser:('T -> 'U option) -> array:'T [] -> 'U option

Full name: Microsoft.FSharp.Collections.Array.tryPick
Type.GetInterfaces() : Type []
MethodInfo.MakeGenericMethod([<ParamArray>] typeArguments: Type []) : MethodInfo
val obs : IObservable
val next : (obj -> unit)
val invoker : IInvoker
val t : IInvoker
abstract member private IInvoker.Invoke : unit -> obj
val unbox : value:obj -> 'T

Full name: Microsoft.FSharp.Core.Operators.unbox
MethodBase.Invoke(obj: obj, parameters: obj []) : obj
MethodBase.Invoke(obj: obj, invokeAttr: BindingFlags, binder: Binder, parameters: obj [], culture: Globalization.CultureInfo) : obj
Multiple items
type AbstractClassAttribute =
  inherit Attribute
  new : unit -> AbstractClassAttribute

Full name: Microsoft.FSharp.Core.AbstractClassAttribute

--------------------
new : unit -> AbstractClassAttribute
Multiple items
type internal Monitor =
  new : unit -> Monitor
  abstract member GetValue : obs:IObservable<'a> -> 'a
  static val mutable private current: Monitor option
  static member SetCurrent : m:Monitor -> IDisposable
  static member Current : Monitor

Full name: Script.Observable.Monitor

--------------------
internal new : unit -> Monitor
Multiple items
type ThreadStaticAttribute =
  inherit Attribute
  new : unit -> ThreadStaticAttribute

Full name: System.ThreadStaticAttribute

--------------------
ThreadStaticAttribute() : unit
Multiple items
type DefaultValueAttribute =
  inherit Attribute
  new : unit -> DefaultValueAttribute
  new : check:bool -> DefaultValueAttribute
  member Check : bool

Full name: Microsoft.FSharp.Core.DefaultValueAttribute

--------------------
new : unit -> DefaultValueAttribute
new : check:bool -> DefaultValueAttribute
Monitor.current: Monitor option
static member internal Monitor.Current : Monitor

Full name: Script.Observable.Monitor.Current
val m : Monitor
static member internal Monitor.SetCurrent : m:Monitor -> IDisposable

Full name: Script.Observable.Monitor.SetCurrent
val oldCurrent : Monitor option
val t : IDisposable
abstract member internal Monitor.GetValue : obs:IObservable<'a> -> 'a

Full name: Script.Observable.Monitor.GetValue
val computed : fn:(unit -> 'a) -> Observable<'a>

Full name: Script.Observable.computed
val fn : (unit -> 'a)
val values : ConcurrentDictionary<IObservable,Choice<Exception,obj>>
Multiple items
type ConcurrentDictionary<'TKey,'TValue> =
  new : unit -> ConcurrentDictionary<'TKey, 'TValue> + 6 overloads
  member AddOrUpdate : key:'TKey * addValueFactory:Func<'TKey, 'TValue> * updateValueFactory:Func<'TKey, 'TValue, 'TValue> -> 'TValue + 1 overload
  member Clear : unit -> unit
  member ContainsKey : key:'TKey -> bool
  member Count : int
  member GetEnumerator : unit -> IEnumerator<KeyValuePair<'TKey, 'TValue>>
  member GetOrAdd : key:'TKey * valueFactory:Func<'TKey, 'TValue> -> 'TValue + 1 overload
  member IsEmpty : bool
  member Item : 'TKey -> 'TValue with get, set
  member Keys : ICollection<'TKey>
  ...

Full name: System.Collections.Concurrent.ConcurrentDictionary<_,_>

--------------------
ConcurrentDictionary() : unit
ConcurrentDictionary(collection: IEnumerable<KeyValuePair<'TKey,'TValue>>) : unit
ConcurrentDictionary(comparer: IEqualityComparer<'TKey>) : unit
ConcurrentDictionary(concurrencyLevel: int, capacity: int) : unit
ConcurrentDictionary(collection: IEnumerable<KeyValuePair<'TKey,'TValue>>, comparer: IEqualityComparer<'TKey>) : unit
ConcurrentDictionary(concurrencyLevel: int, collection: IEnumerable<KeyValuePair<'TKey,'TValue>>, comparer: IEqualityComparer<'TKey>) : unit
ConcurrentDictionary(concurrencyLevel: int, capacity: int, comparer: IEqualityComparer<'TKey>) : unit
val subs : Dictionary<IObservable,IDisposable>
val observable : Observable<'a>
val refresh : (unit -> unit)
val obses : HashSet<IObservable>
Multiple items
type HashSet<'T> =
  new : unit -> HashSet<'T> + 3 overloads
  member Add : item:'T -> bool
  member Clear : unit -> unit
  member Comparer : IEqualityComparer<'T>
  member Contains : item:'T -> bool
  member CopyTo : array:'T[] -> unit + 2 overloads
  member Count : int
  member ExceptWith : other:IEnumerable<'T> -> unit
  member GetEnumerator : unit -> Enumerator<'T>
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  ...
  nested type Enumerator

Full name: System.Collections.Generic.HashSet<_>

--------------------
HashSet() : unit
HashSet(comparer: IEqualityComparer<'T>) : unit
HashSet(collection: IEnumerable<'T>) : unit
HashSet(collection: IEnumerable<'T>, comparer: IEqualityComparer<'T>) : unit
val t : Monitor
abstract member internal Monitor.GetValue : obs:IObservable<'a> -> 'a
val obs : IObservable<'b>
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
HashSet.Add(item: IObservable) : bool
val lv : IObservableValue<'b>
property IObservableValue.HasValue: bool
property IObservableValue.Value: 'b
ConcurrentDictionary.TryGetValue(key: IObservable, value: byref<Choice<Exception,obj>>) : bool
val value : obj
val value : Choice<exn,'a> option
val using : resource:'T -> action:('T -> 'U) -> 'U (requires 'T :> IDisposable)

Full name: Microsoft.FSharp.Core.Operators.using
static member internal Monitor.SetCurrent : m:Monitor -> IDisposable
val ex : ObservableException
property Exception.InnerException: exn
val pair : KeyValuePair<IObservable,IDisposable>
val ofSeq : source:seq<'T> -> 'T []

Full name: Microsoft.FSharp.Collections.Array.ofSeq
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
HashSet.Contains(item: IObservable) : bool
property KeyValuePair.Key: IObservable
property KeyValuePair.Value: IDisposable
Dictionary.Remove(key: IObservable) : bool
Dictionary.ContainsKey(key: IObservable) : bool
val on : (Choice<Exception,obj> -> unit)
val value : Choice<Exception,obj>
module Impl

from Script
Object.GetType() : Type
member Observable.PublishError : ex:Exception -> unit
member Observable.Publish : value:'a -> unit
Multiple items
type AutoOpenAttribute =
  inherit Attribute
  new : unit -> AutoOpenAttribute
  new : path:string -> AutoOpenAttribute
  member Path : string

Full name: Microsoft.FSharp.Core.AutoOpenAttribute

--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
val t : IObservable<'T>
member IObservable.Value : 'T

Full name: Script.ObservableExtensions.Value
Multiple items
module Observable

from Script

--------------------
module Observable

from Microsoft.FSharp.Control

--------------------
type Observable<'a> =
  interface IObservableValue<'a>
  interface IObservable<'a>
  new : unit -> Observable<'a>
  member Publish : value:'a -> unit
  member PublishError : ex:Exception -> unit

Full name: Script.Observable<_>


 Implementation of IObservable<T> and IObservableValue<T>.


--------------------
new : unit -> Observable<'a>
Multiple items
type internal Monitor =
  new : unit -> Monitor
  abstract member GetValue : obs:IObservable<'a> -> 'a
  static val mutable private current: Monitor option
  static member SetCurrent : m:Monitor -> IDisposable
  static member Current : Monitor

Full name: Script.Observable.Monitor

--------------------
internal new : unit -> Observable.Monitor
property Observable.Monitor.Current: Observable.Monitor
abstract member internal Observable.Monitor.GetValue : obs:IObservable<'a> -> 'a
member IObservable.Subscribe : next:('T -> unit) * error:(Exception -> unit) -> IDisposable

Full name: Script.ObservableExtensions.Subscribe
val next : ('T -> unit)
member IObservable.Subscribe : callback:('T -> unit) -> IDisposable
IObservable.Subscribe(observer: IObserver<'T>) : IDisposable
member IObservable.Subscribe : next:('T -> unit) * error:(Exception -> unit) -> IDisposable
Multiple items
type EntryPointAttribute =
  inherit Attribute
  new : unit -> EntryPointAttribute

Full name: Microsoft.FSharp.Core.EntryPointAttribute

--------------------
new : unit -> EntryPointAttribute
val main : args:string [] -> int

Full name: Script.main
val args : string []
val obs1 : Observable<int>
val d1 : IDisposable
member IObservable.Subscribe : callback:('T -> unit) -> IDisposable
member IObservable.Subscribe : next:('T -> unit) * error:(Exception -> unit) -> IDisposable
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val obs2 : Observable<int>
val d2 : IDisposable
val c : Observable<int>
property IObservable.Value: 'T
val dc : IDisposable
val r : Random
Multiple items
type Random =
  new : unit -> Random + 1 overload
  member Next : unit -> int + 2 overloads
  member NextBytes : buffer:byte[] -> unit
  member NextDouble : unit -> float

Full name: System.Random

--------------------
Random() : unit
Random(Seed: int) : unit
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
Multiple items
type Thread =
  inherit CriticalFinalizerObject
  new : start:ThreadStart -> Thread + 3 overloads
  member Abort : unit -> unit + 1 overload
  member ApartmentState : ApartmentState with get, set
  member CurrentCulture : CultureInfo with get, set
  member CurrentUICulture : CultureInfo with get, set
  member DisableComObjectEagerCleanup : unit -> unit
  member ExecutionContext : ExecutionContext
  member GetApartmentState : unit -> ApartmentState
  member GetCompressedStack : unit -> CompressedStack
  member GetHashCode : unit -> int
  ...

Full name: System.Threading.Thread

--------------------
Thread(start: ThreadStart) : unit
Thread(start: ParameterizedThreadStart) : unit
Thread(start: ThreadStart, maxStackSize: int) : unit
Thread(start: ParameterizedThreadStart, maxStackSize: int) : unit
Thread.Sleep(timeout: TimeSpan) : unit
Thread.Sleep(millisecondsTimeout: int) : unit
Raw view Test code New version

More information

Link:http://fssnip.net/j6
Posted:10 years ago
Author:Tim Robinson
Tags: iobservable rx