FSharpx is a library for the .NET platform implementing general functional constructs on top of the F# core library. Its main target is F# but it aims to be compatible with all .NET languages wherever possible.
It currently implements:
- Several standard monads: State, Reader, Writer, Either, Continuation, Distribution
- Purely functional data structures: Queues, double-ended Queues, BottomUpMergeSort, RandomAccessList, Vector
- Validation applicative functor
- General functions like flip
- Additional functions around collections
- Functions to make C# - F# interop easier
- Async and Observable extensions
This library implements various extensions for asynchronous programming
using F# asynchronous workflows and F# agents (the MailboxProcessor
type
in the standard F# library). It defines asynchronous sequences that represent
asynchronous operations returning multiple values (such as reading data from
a stream in chunks), several reusable F# agents and numerous extensions.
- Samples that demonstrate how to use most of the extensions can be found in the samples directory
Asynchronous sequences can be used to work with asynchronous computations that return
multiple results. A value of type AsyncSeq<'T>
can be started (just like an asynchronous
workflow) and it eventually returns. The result is either a special value representing
the end of the sequence or a value of type 'T
(head) together with the rest of the
asynchronous sequence (tail) of type AsyncSeq<'T>
.
Unlike IObservable<'T>
, asynchronous sequences are not push-based. The code that
generates the next value of the asynchronous sequence starts only after previous elements
have been processed. This makes it possible to easily write computations that return
results as long as some component is using them.
However, IObservable<'T>
values can
be converted to asynchronous sequences. The AsyncSeq.ofObservable
combinator creates an
asynchronous sequence that discards values produced by the observable while the
asynchronous sequence was blocked. The AsyncSeq.ofObservableBuffered
combinator stores
all produced values in an unbounded buffer and returns the values from the buffer as soon
as the user of asynchronous sequence requestst the next element.
The library defines an F# computation expression for workfing with asynchronous sequences. For example, sequence that emits numbers in 1 second intervals can be defined as follows:
let rec numbers n = asyncSeq {
yield n
do! Async.Sleep(1000)
yield! numbers (n + 1) }
Asynchronous workflows and asynchronous sequences can use the for
construct to iterate
over all elements of an asynchronous sequence. For example:
let rec evenNumbers = asyncSeq {
for n in numbers 0 do
if n%2=0 then yield n }
The library also provides numerous combinators (similar to functions from the Seq
module).
The result of operations that aggregate values of an asynchronous sequence is an asynchronous
workflow that returns a single value:
let rec sumTenEvenSquares =
numbers 0
|> AsyncSeq.filter (fun n -> n%2 = 0)
|> AsyncSeq.map (fun n -> n*n)
|> AsyncSeq.fold (+) 0
let n =
sumTenEvenSquares
|> Async.RunSynchronously
For some examples that use (earlier versions) of asynchronous sequences, see also the following two F# snippets: first and second.
The library implements several reusable agents for building concurrent applications:
-
Agent is a simple type aliast for
MailboxProcessor
that is more convenient to use -
AutoCancelAgent wraps the standard F# agent and adds support for stopping of the agent's body using the
IDisposable
interface (the type automatically creates a cancellation token, uses it to start the underlying agent and cancels it when the agent is disposed). For example, see this F# snippet. -
BatchProcessingAgent can be used to implement batch processing. It creates groups of messages (added using the
Enqueue
method) and emits them using theBatchProduced
event. A group is produced when it reaches the maximal size or after the timeout elapses. -
BlockingQueueAgent implements an asynchronous queue with blocking put and blocking get operations. It can be used to implement the producer-consumer concurrent pattern. The constructor of the agent takes the maximal size of the buffer.
The library implements extensions for using IObservable<'T>
type from F# asynchronous
workflows. An overloaded extension method Async.AwaitObservable
can be used to wait
for an occurrence of an event (or other observable action):
let counter n = async {
printfn "Counting: %d" n
let! _ = form.MouseDown |> Async.AwaitObservable
return! counter (n + 1) }
Overloaded version of the method allows waiting for the first of multiple events. The
method asynchronously returns Choice<'T1, 'T2>
value that can be used to determine
which of the events has occurred.
For examples using this method see Chapter 16 of Real World Functional Programming
(some examples are available in a free excerpt from the chapter). The
Async.AwaitObservable
method should be used instead of Async.AwaitEvent
to avoid
memory leaks (see also related StackOverflow discussion)
FSharpx provides some very interesting F# type providers. At the moment we have:
- FSharpx.TypeProviders.AppSettings which generates setters and getters for application settings files.
- FSharpx.TypeProviders.Documents which allows strongly typed access to JSON, XML and CSV files.
- FSharpx.TypeProviders.Excel which provides strongly typed access to Excel spread sheets.
- FSharpx.TypeProviders.Graph which includes type providers for state machines and graphs.
- FSharpx.TypeProviders.Math which contains a type provider for vector data structures.
- FSharpx.TypeProviders.Regex which allows to access regular expressions in a strongly typed manner.
- FSharpx.TypeProviders.Machine which provides strongly typed access to the Registry and the file system.
- FSharpx.TypeProviders.Xaml which includes a type provider for XAML files and therefor enables to use Visual Studios’s WPF Designer from F#.
- FSharpx.TypeProviders.Freebase which allows to access the Freebase database with strong typing.
At the moment all type providers should work with .NET 4.0 and .NET 4.5 and F# 3.0.
In order to build and test the type providers do the following:
- Open FSharpx.WithTypeProviders.sln with Visual Studio 2012
- Set FSharpx.TypeProviders as startup project
- In the properties of FSharpx.TypeProviders:
- Set the start action to "external program" and "C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe"
- Set the command line argument to "C:\code\fsharpx\FSharpx.TypeProviders.Tests.sln" (adjust the path to match to your system)
- Run the project --> A new Visual Studio 2012 instance should opened with FSharpx.TypeProviders.Tests.sln
Read the wiki page about Build