Freckle


Freckle

Simple monadic Functional Reactive Programming for F#

The Freckle library can be installed from NuGet:
PM> Install-Package Freckle

Quick Introduction

Namespace and referecing

1: 
open Freckle

Setting up a sampler and running

Create a sampler that prints the timespan it samples over

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
let sampler count =
    sample {
        let! currentSpan = Sample.period
        let startedAt = (Time.toDateTime currentSpan.Beginning)
        let endedAt = (Time.toDateTime currentSpan.Finish)
        printfn "%d: Sampling %A -> %A" count startedAt endedAt
        return count + 1
    } |> SampleAsync.ofSample

Sample.sampleForever Clock.systemUtc sampler 0
|> Async.RunSynchronously

Guaranteed Fixed interval updates

Create a sampler that counts every second from 0 and is resistentent to computer lagspike

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
let countSecondsSampler count =
    sample {
        let! pulses = Feed.pulse 1
        return! Feed.foldPast (fun c _ -> c + 1) count pulses
    } |> SampleAsync.ofSample

Sample.sampleForever Clock.systemUtc countSecondsSampler 0
|> Async.RunSynchronously

Best attempt Fixed interval updates

Creates a sampler that does something every second, but doesn't care if a step is skipped due to a lagspike

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
let render =
    async {
        return printfn "Pretend like this is graphic rendering" 
    }

let renderingSampler () =
    sample {
        let! pulses = Feed.pulseUpto 1 //Notice it's pulseUpto
        return! Feed.transition (fun _ _ -> render) () pulses
    }

Sample.sampleForever Clock.systemUtc renderingSampler ()
|> Async.RunSynchronously

Listening to events

Listen to external events and print their content to the console

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
async {
    let syncClock = Clock.synchronized Clock.systemUtc
    let! mb = Mailbox.createWithExpiration (Expire.After (Time.ofSeconds 30))  syncClock

    let renderingSampler mb () =
        sampleAsync {
            let! events = Mailbox.read mb |> SampleAsync.ofAsync
            do! Mailbox.clear |> SampleAsync.ofAsync
            return! Feed.foldPast (fun _ msg -> printfn "revieved %s" msg) () events
                    |> SampleAsync.ofSample
        }

    do! Sample.sampleForever syncClock (renderingSampler mb) ()
}
|> Async.RunSynchronously

Further Reading

  • Tutorial contains a further explanation of this sample library.

  • API Reference contains automatically generated documentation for all types, modules and functions in the library. This includes additional brief samples on using most of the functions.

Contributing and copyright

The project is hosted on GitHub where you can report issues, fork the project and submit pull requests. If you're adding a new public API, please also consider adding samples that can be turned into a documentation. You might also want to read the library design notes to understand how it works.

The library is available under Public Domain license, which allows modification and redistribution for both commercial and non-commercial purposes. For more information see the License file in the GitHub repository.

namespace System
namespace System.Threading
namespace System.Threading.Tasks
namespace System.Threading.Tasks.Dataflow
namespace Freckle
val sampler : count:int -> Sample<Async<int>>

Full name: Index.sampler
val count : int
val sample : Sample.ComputationalExpression.Builder

Full name: Freckle.ComputationExpression.sample
val currentSpan : Period
Multiple items
module Sample

from Freckle

--------------------
type Sample<'a> = Period -> 'a

Full name: Freckle.Sample<_>
val period : Sample<Period>

Full name: Freckle.Sample.period
val startedAt : System.DateTime
type Time =
  {Ticks: Ticks;}
  override ToString : unit -> string
  static member between : a:Time -> b:Time -> Time
  static member maxValue : Time
  static member origin : Time
  static member ofDateTime : d:DateTime -> Time
  static member ofDays : days:int32 -> Time
  static member ofHours : hour:int32 -> Time
  static member ofMicroseconds : microSec:int32 -> Time
  static member ofMilliseconds : ms:int32 -> Time
  static member ofMinutes : min:int32 -> Time
  static member ofSeconds : sec:int32 -> Time
  static member ( + ) : t1:Time * t2:Time -> Time
  static member ( - ) : t1:Time * t2:Time -> Time
  static member ticks : t:Time -> Ticks
  static member time : t:Ticks -> Time
  static member toDateTime : t:Time -> DateTime

Full name: Freckle.Time
static member Time.toDateTime : t:Time -> System.DateTime
Period.Beginning: Time
val endedAt : System.DateTime
Period.Finish: Time
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
module SampleAsync

from Freckle
val ofSample : x:Sample<'a> -> Sample<Async<'a>>

Full name: Freckle.SampleAsync.ofSample
val sampleForever : clock:Clock -> sampler:('s -> Sample<Async<'s>>) -> state:'s -> Async<'a>

Full name: Freckle.Sample.sampleForever
Multiple items
union case Clock.Clock: Async<Time> -> Clock

--------------------
module Clock

from Freckle.Clock

--------------------
module Clock

from Freckle

--------------------
type Clock = | Clock of Async<Time>

Full name: Freckle.Clock.Types.Clock
val systemUtc : Clock

Full name: Freckle.Clock.Clock.systemUtc
Multiple items
module Async

from Freckle

--------------------
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task -> Async<unit>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:System.Threading.CancellationToken -> 'T
val countSecondsSampler : count:int -> Sample<Async<int>>

Full name: Index.countSecondsSampler
val pulses : Feed<Time>
Multiple items
union case Feed.Feed: LazyList<Time * 'e> -> Feed<'e>

--------------------
module Feed

from Freckle

--------------------
type Feed<'e> =
  | Feed of LazyList<Time * 'e>
  override ToString : unit -> string

Full name: Freckle.Feed<_>
val pulse : pulsePerSecond:int -> Sample<Feed<Time>>

Full name: Freckle.Feed.pulse
val foldPast : f:('s -> 'a -> 's) -> state:'s -> fr:Feed<'a> -> Sample<'s>

Full name: Freckle.Feed.foldPast
val c : int
val render : Async<unit>

Full name: Index.render
val async : AsyncBuilder

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
val renderingSampler : unit -> Sample<Async<unit>>

Full name: Index.renderingSampler
val pulseUpto : pulsePerSecond:int -> Sample<Feed<Time>>

Full name: Freckle.Feed.pulseUpto
val transition : f:('s -> 'a -> Async<'s>) -> state:'s -> allFeed:Feed<'a> -> Sample<Async<'s>>

Full name: Freckle.Feed.transition
val syncClock : Clock
val synchronized : Clock -> Clock

Full name: Freckle.Clock.Clock.synchronized
val mb : Mailbox<string>
Multiple items
module Mailbox

from Freckle

--------------------
type Mailbox<'e> =
  {Post: 'e -> Async<unit>;
   Read: Async<Feed<'e>>;
   Clear: Async<unit>;
   AwaitMail: Async<unit>;}

Full name: Freckle.Mailbox<_>
val createWithExpiration : expire:Expire -> clock:Clock -> Async<Mailbox<'a>>

Full name: Freckle.Mailbox.createWithExpiration
type Expire =
  | Never
  | After of Time

Full name: Freckle.Expire
union case Expire.After: Time -> Expire
static member Time.ofSeconds : sec:int32 -> Time
val renderingSampler : (Mailbox<string> -> unit -> Sample<Async<unit>>)
val sampleAsync : SampleAsync.ComputationalExpression.Builder

Full name: Freckle.ComputationExpression.sampleAsync
val events : Feed<string>
val read : mb:Mailbox<'a> -> Async<Feed<'a>>

Full name: Freckle.Mailbox.read
val ofAsync : x:Async<'a> -> Sample<Async<'a>>

Full name: Freckle.SampleAsync.ofAsync
val clear : mb:Mailbox<'a> -> Async<unit>

Full name: Freckle.Mailbox.clear
val msg : string
Fork me on GitHub