Joinads is a general-purpose extension of the F# *computation expression* syntax (also called *monadic* syntax)
in F# and is mainly useful for concurrent, parallal and reactive programming. The extension adds a new
piece of notation, written `match!`

that can be used to compose computations using *non-deterministic choice*,
*parallel composition* and *aliasing*.

For example, when programming with futures (the `Task<T>`

type), you may want to implement logical "or" operator
for tasks that returns `true`

immediately when the first task completes returning `true`

. When programming with
events (the `IObservable<T>`

type in .NET), we'd like to wait for the event that happens first. Finally, when
programming using agents, we sometimes need to wait only for certain types of messages. All of these problems can
be solved, but require the use of (sometimes fairly complicated) functions.

Joinads make it possible to solve them directly using the `match!`

syntax. For example, the following snippet
shows the "or" operator for tasks:

open System.Threading.Tasks open FSharp.Extensions.Joinads /// Returns a Task that produces the given /// value after the specified time let after (time:int) res = (...) /// Short-circuiting implementation /// of the 'or' operator for tasks. let taskOr t1 t2 = future { match! t1, t2 with | true, ? -> return true | ?, true -> return true | a, b -> return a || b } // Apply 'or' to a task that returns true after 100ms // and a task that returns false after 2 sec. let res = taskOr (after 100 true) (after 2000 true) printfn "\nCompleted with result: %b" res.Result

The `match!`

notation intentionally resembles pattern matching. However, instead of pattern matching on actual
values, we are pattern matching on computations of type `Task<'T>`

. The patterns used in the clauses of `match!`

can be either normal F# patterns or a special pattern `?`

which specifies that the clause can run even if
the value of the corresponding computation is not available.

In the above example, the last clause specifies that both of the computations have to complete,
producing `bool`

values `a`

and `b`

. When the clause matches, the result is calculated as `a || b`

.
The first two clauses are more interesting. For example, the pattern `true, ?`

specifies that
the first computation should produce `true`

, but the second does not have to finish for the
clause to match. As a result, when one of the computations returns `true`

, the `match!`

construct
does not wait for the other computation and immediately returns `true`

.

If you run the above code (run the last two lines separately to get a readable output), then you
can see that the task created by `taskOr`

completes after 100ms, even though the second argument
of `taskOr`

is still running. If you change the result of the first argument to `false`

, the
computation needs to wait for the second value, and so it take 2 seconds to complete.

Aside from the support for *joinads*, the F# interactive console on this site also supports
syntax for programming with *applicative functors* (also called *idioms*). Applicative
functors are an abstract notion of computations that is weaker (and thus more common)
than monads - every monad is an applicative functor, but not all applicative functors
are monads. For more information about the extensions for applicative functors, see
a blog post that discusses them.

Joinads are an abstract concept that describes what operations are required to implement pattern matching on monadic computations. This means that the general idea can be used in any programming language.

In addition, languages that already have some syntactic support for writing monadic
computations can be extended with a special syntax for joinads. This tutorial shows numerous
examples of the `match!`

syntax in F#, but there is also an implementation for Haskell.

The Haskell extension is currently available as a patch on GitHub and you can
find more information in a our papers on joinads
or in the GHC Trac description. Akin to
the `do`

notation and `case`

construct, the patch adds `docase`

notation, which allows
pattern matching on monadic computations that implement three additional operation.
The previous F# example could be written in Haskell as follows:

taskOr t1 t2 = docase t1, t2 of True, ? -> return True ?, True -> return True a, b -> return $ a || b

The syntax is quite similar to the F# version, but there are several differences. Most notably, thanks to type-classes, the above code is polymorphic over the actual joinad - any type that implements a couple of involved type-classes can be used with this function.

namespace System

namespace System.Threading

namespace System.Threading.Tasks

namespace FSharp

namespace FSharp.Extensions

namespace FSharp.Extensions.Joinads

val after : int -> 'a -> Task<'a>

Full name: TryJoinads.after

Returns a Task that produces the given

value after the specified time

Full name: TryJoinads.after

Returns a Task that produces the given

value after the specified time

val time : int

type: int

inherits: System.ValueType

type: int

inherits: System.ValueType

Multiple items

val int : 'T -> int (requires member op_Explicit)

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

--------------------

type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>

type: int<'Measure>

inherits: System.ValueType

--------------------

type int = int32

Full name: Microsoft.FSharp.Core.int

type: int

inherits: System.ValueType

val int : 'T -> int (requires member op_Explicit)

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

--------------------

type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>

type: int<'Measure>

inherits: System.ValueType

--------------------

type int = int32

Full name: Microsoft.FSharp.Core.int

type: int

inherits: System.ValueType

val res : 'a

future { System.Threading.Thread.Sleep(time)

return res }

return res }

val taskOr : Task<bool> -> Task<bool> -> Task<bool>

Full name: TryJoinads.taskOr

Short-circuiting implementation

of the 'or' operator for tasks.

Full name: TryJoinads.taskOr

Short-circuiting implementation

of the 'or' operator for tasks.

val t1 : Task<bool>

type: Task<bool>

inherits: Task

type: Task<bool>

inherits: Task

val t2 : Task<bool>

type: Task<bool>

inherits: Task

type: Task<bool>

inherits: Task

val future : FutureBuilder

Full name: FSharp.Extensions.Joinads.TopLevelValues.future

Full name: FSharp.Extensions.Joinads.TopLevelValues.future

val a : bool

type: bool

inherits: System.ValueType

type: bool

inherits: System.ValueType

val b : bool

type: bool

inherits: System.ValueType

type: bool

inherits: System.ValueType

val res : Task<bool>

Full name: TryJoinads.res

type: Task<bool>

inherits: Task

Full name: TryJoinads.res

type: Task<bool>

inherits: Task

val printfn : Printf.TextWriterFormat<'T> -> 'T

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

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

property Task.Result: bool