TransAlt


TransAlt

This project is a proof of concept implementation of async computation workflows composition with non determenistic choice, merge and bind based on immutable state with lock detection. Uses ideas from Stm,Hopac,Joinads.

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

Example

This example demonstrates lock detection and resolution.

 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: 
#r "TransAlt/TransAlt.dll"
open TransAlt
open Alt
open Channel
open Lens
open System.Threading
type DeadlockSt =
    { get1C: Channel<unit>; 
      get2C: Channel<unit>;}

    static member get1 =
        { get = fun r -> r.get1C; 
          set = fun (r,v) -> { r with get1C = v }}

    static member get2 =
        { get = fun r -> r.get2C; 
          set = fun (r,v) -> { r with get2C = v }}

let deadlockSt = {get1C = EmptyUnbounded "get1C"
                  get2C = EmptyUnbounded "get2C"} 

let task1 =   tranB{
        let! x = DeadlockSt.get1.deq()
        do! after 100 ()
        let! y = DeadlockSt.get2.deq()
        do! DeadlockSt.get1.enq()
        do! DeadlockSt.get2.enq()
        return ()
    }
let task2 =  tranB{
        let! x = DeadlockSt.get2.deq()
        do! after 100 ()
        let! y = DeadlockSt.get1.deq()
        do! DeadlockSt.get1.enq()
        do! DeadlockSt.get2.enq()
        return ()
    }
let task3 = tranB{
        do! DeadlockSt.get1.enq()
        do! DeadlockSt.get2.enq()
        return ()
    }
//lock detection
mergeB{
    case task1
    case task2
    case task3
} |> pickWithResultState deadlockSt |> Async.RunSynchronously |> printfn "%A"
//lock resolution
mergeChooseXs[task1;task2;task3] |> pickWithResultState deadlockSt |> Async.RunSynchronously |> printfn "%A"

Some more info

Samples & documentation

The library comes with comprehensible documentation. It can include tutorials automatically generated from *.fsx files in the content folder. The API reference is automatically generated from Markdown comments in the library implementation.

  • 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 TransAlt
module Alt

from TransAlt
module Channel

from TransAlt
module Lens

from TransAlt
namespace System
namespace System.Threading
type DeadlockSt =
  {get1C: Channel<unit>;
   get2C: Channel<unit>;}
  static member get1 : Lens<DeadlockSt,Channel<unit>>
  static member get2 : Lens<DeadlockSt,Channel<unit>>

Full name: Index.DeadlockSt
DeadlockSt.get1C: Channel<unit>
Multiple items
module Channel

from TransAlt

--------------------
type Channel<'a> =
  {name: string;
   maxCount: int option;
   xs: 'a list;
   rxs: 'a list;}
  member Get : unit -> OpResp<Channel<'a> * 'a>
  member Put : x:'a -> OpResp<Channel<'a>>
  member AsString : string
  member Count : int
  member IsEmpty : bool

Full name: TransAlt.Channel.Channel<_>
Multiple items
val unit : unit -> Alt<'a,unit> (requires reference type)

Full name: TransAlt.Alt.unit

--------------------
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
DeadlockSt.get2C: Channel<unit>
static member DeadlockSt.get1 : Lens<DeadlockSt,Channel<unit>>

Full name: Index.DeadlockSt.get1
val r : DeadlockSt
val set : elements:seq<'T> -> Set<'T> (requires comparison)

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.set
val v : Channel<unit>
static member DeadlockSt.get2 : Lens<DeadlockSt,Channel<unit>>

Full name: Index.DeadlockSt.get2
val deadlockSt : DeadlockSt

Full name: Index.deadlockSt
val EmptyUnbounded : name:string -> Channel<'a>

Full name: TransAlt.Channel.EmptyUnbounded
val task1 : Alt<DeadlockSt,unit>

Full name: Index.task1
val tranB : TransactionBuilder

Full name: TransAlt.Alt.tranB
val x : unit
property DeadlockSt.get1: Lens<DeadlockSt,Channel<unit>>
static member ChEx.deq : qlens:Lens<'s,Channel<'v>> -> Alt<'s,'v> (requires reference type)
val after : ms:int -> v:'a -> Alt<'b,'a> (requires reference type)

Full name: TransAlt.Alt.after
val y : unit
property DeadlockSt.get2: Lens<DeadlockSt,Channel<unit>>
static member ChEx.enq : qlens:Lens<'s,Channel<'v>> * x:'v -> Alt<'s,unit> (requires reference type)
val task2 : Alt<DeadlockSt,unit>

Full name: Index.task2
val task3 : Alt<DeadlockSt,unit>

Full name: Index.task3
val mergeB : MergeBuilder

Full name: TransAlt.Alt.mergeB
custom operation: case (Alt<'a,'b>)

Calls MergeBuilder.Case
val pickWithResultState : state:'a -> alt:Alt<'a,'b> -> Async<TransactionResult<'b> * 'a> (requires reference type)

Full name: TransAlt.Alt.pickWithResultState
Multiple items
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<'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:CancellationToken -> 'T
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val mergeChooseXs : xs:seq<Alt<'s,'r>> -> Alt<'s,seq<'r>> (requires reference type)

Full name: TransAlt.Alt.mergeChooseXs
Fork me on GitHub