Signals in Gjallarhorn
One of the core types in Gjallarhorn is a Signal.
A signal represents a value that changes over time, and has the following properties: - A current value, which can always be fetched - A mechanism to signal changes to subscribers that the value has been updated
You can think if a signal as a window into data that changes over time. It's similar to an observable, and even implements IObservable for compatibility with other libraries, except that it always has a current value.
The simplest signal can be created via Signal.constant
:
1: 2: 3: 4: 5: 6: 7: 8: 9: |
|
As it's name suggests, Signal.constant
takes a constant value and binds it into a signal, which is represented via the ISignal<'a>
interface.
ISignal<'a>
provides a simple .Value
property, which we can use to fetch the current value at any point.
All mutables in Gjallarhorn also implement ISignal<'a>
, allowing mutables to be used as signals as well. The Signal
module provides functionality
which allows you to subscribe to changes on signals:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: |
|
Signals can also be filtered or transformed:
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: |
|
Signals can be combined by using Signal.map2
, and even higher arity mapping functions:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: |
|
Signals are also closely related to observables. The main difference between an ISignal<'a>
and an IObservable<'a>
is that the former has the
notion of a value (represented in the Value
property) which always exists and is current.
As these are so closely related, ISignal<'a>
directly implements IObservable<'a>
, and there is a function to convert from IObservable<'a>
included in the Signal
module.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: |
|
It is also possible to use signals by closing over them with functions. This provides a clean mechanism for working with configuration.
For example:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: |
|
Now, let's move on to Mutables in Gjallarhorn.
Full name: Signals.s
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
Full name: Signals.m
Full name: Signals.source
Full name: Signals.filtered
Full name: Signals.final
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
Full name: Signals.a
Full name: Signals.b
Full name: Signals.v1
Full name: Signals.c
Full name: Signals.d
Full name: Signals.v2
Full name: Signals.e
module Event
from Microsoft.FSharp.Control
--------------------
type Event<'T> =
new : unit -> Event<'T>
member Trigger : arg:'T -> unit
member Publish : IEvent<'T>
Full name: Microsoft.FSharp.Control.Event<_>
--------------------
type Event<'Delegate,'Args (requires delegate and 'Delegate :> Delegate)> =
new : unit -> Event<'Delegate,'Args>
member Trigger : sender:obj * args:'Args -> unit
member Publish : IEvent<'Delegate,'Args>
Full name: Microsoft.FSharp.Control.Event<_,_>
--------------------
new : unit -> Event<'T>
--------------------
new : unit -> Event<'Delegate,'Args>
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
Full name: Signals.observable
Full name: Signals.s
Full name: Signals.obs
member Subscribe : observer:IObserver<'T> -> IDisposable
Full name: System.IObservable<_>
from Microsoft.FSharp.Control
Full name: Microsoft.FSharp.Control.Observable.add
namespace System.Configuration
--------------------
type Configuration =
{Author: string;
AutoPublish: bool;}
Full name: Signals.Configuration
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
Full name: Microsoft.FSharp.Core.bool
Full name: Signals.config
Full name: Signals.workWithConfig
Full name: Signals.operation