FsFlow is a library for defining variables and Excel-like reactive computations. It uses a combination of depth-first and sorted queue strategies for refreshing values. Dependent variables created with Flow.map compute immediately, while those created with the comp computation expression are sorted and delayed until all map refreshes are done. You can delay refreshing these, while assigning new values to multiple source variables by the line use d = Flow.defer() in ...expr...

Main fuctions and objects

Flow.var v creates a bindable variable with initial value v.

Flow.prop getValue setValue creates a bindable variable with an external backing store. For example:

let extProp = ref 1 
let extPropVar = Flow.prop (fun () -> !extProp) (fun v -> extProp := v)

Operators ! and := are redefined to use get_Value and set_Value extending their original functioning as operators on the ref<_> type.

Flow.map mapping source creates a dependent variable whose value is the actual value of mapping !source.
Flow.lmap is a lazy version: mapped value is not created immediately, only when needed.

map2, lmap2, map3, lmap3 are multiple variable versions.

Flow.onChange action source creates an IDisposable that is subscribed to changes in source, and executes action v on every change where v is the new value of source.

Flow.publish creates an object implementing INotifyPropertyChanged, and has a Value property. You can bind to this from XAML. publishS lets you override set_Value, publishA sets the value of the underlying variable, and calls an additional function as a side effect.

Flow.publishOpt and Flow.publishNull lets you expose an option<_> typed variable as a null-valued or Nullable type respectively.

Flow.publishEnum has an indexed Item property where the index should be a name of an underlying enum value. (See the sample.)

Flow.constant v is an unchangeable variable.

Flow.command name source execute creates an ICommand with some additional properties: Name has the value name if the source variable's current value is Enabled, and n if it's EnabledNamed n. In these two cases CanExecute is true. The Error property has value em is the source variable's current value is ErrorMessage em.

Flow.commandE name execute creates an ICommand that is always enabled.

Computed variables must be created specifying a level value ranging 0-15. comp0, ... comp3 are already defined, as well as comp = compL 15. It is recommended that you create computations that use bound variables from only lower or the same level. If you don't need to bind the created dependent variable in another computation, then comp is a good choice. This achieves that no computations are needlessly refreshed multiple times.

Limits: the maximum number of mapped variables created is 231=2147483648. There are 16 available levels of computed variables, and 16 is the maximum depth (nested let! bindings) in a comp variable. The maximum number of computed variables for any level is 223=8388608. If you need more of anything, you can modify the Ticket type and module in Helpers.fs.


let ``if !a then !b + 1 else !c + 2`` =
    comp {
        let! av = a
        if av then
            let! bv = b
            return bv + 1
            let! cv = c
            return cv + 2

This computation automatically binds the variable a and if the current value of a is true then b else c. If the value of a changes, it unsubscribes from b or c and subscribes to the other.


Flow.set v creates a set valued variable.

Flow.publishSet source publishes a VariableSet by the IList and INotifyCollectionChanged interfaces.

Flow.intersect, Flow.union, Flow.difference are set operations for set variables.

Flow.onSetChange onAdded onRemoved onCleared source creates an IDisposable that is subscribed to changes in source and executes the given functions.

Flow.filterSet filter source creates a variable set, that always contain the elements of source for which the filter function returns true.

mapSet level mapping collect source creates computed variables for each element in source. When the mapping function returns Created var then var will be disposed if the source element is removed. The final value is created by applying collect on the current values of the ven by mapping. This last step is a lazy computation.

Last edited May 23, 2013 at 7:51 PM by JankoA, version 3


No comments yet.