2. First class .Net Language citizen
Multi paradigm language
Functional
Object orientated
Well suited for:
Financial
Statistical
Testing
Event processing
Tool development
General purpose components
General server-side development
3. Referential transparency / deterministic
Immutability
First class functions
Higher order functions
Recursion
4. Reasoning
Code behaves in a consistent understandable manner
Safety
Contents of variables are always as expected no unknown
mutation
Reduction code
Code can be safely reused
Data Sharing
Threading is easier and locks are no longer needed
Testing
Concise functions that are easy to test
5. Code reduction
Typically around 70%
Increased performance
Easy to parallelise functions
Increased productivity
Common to experience 50% boost
Increasing importance of multi-core and cloud
F# facilitates building multi-core friendly code
Reduced maintenance costs
Bugs and compiler issues are found earlier, typically during REPL
(Read-Eval-Print Loop is for interactive compilation and exploration)
Easy to create Domain specific languages
7. C# already had functional features
LINQ, Lambda expressions, predicates, closures
Uses the same .Net libraries
Can be consumed by other .Net languages
Start with core components
Algorithm development
Data analysis
parallel batch processing
rapid prototyping
Testing
8. Object pool -C#
Example taken from
the MSDN website
2Types
20 Lines in base class
41 lines in derived class
using System.Collections.Generic;
using System.Diagnostics;
namespace System.Collections.Concurrent
{
/// <summary>Provides a thread-safe object pool.</summary>
/// <typeparam name="T">Specifies the type of the elements stored in the pool.</typeparam>
[DebuggerDisplay("Count={Count}")]
[DebuggerTypeProxy(typeof(IProducerConsumerCollection_DebugView<>))]
public sealed class ObjectPool<T> : ProducerConsumerCollectionBase<T>
{
private readonlyFunc<T> _generator;
/// <summary>Initializes an instance of the ObjectPool class.</summary>
/// <param name="generator">The function used to create items when no items exist in the
pool.</param>
public ObjectPool(Func<T> generator) : this(generator, new ConcurrentQueue<T>()) { }
/// <summary>Initializes an instance of the ObjectPool class.</summary>
/// <param name="generator">The function used to create items when no items exist in the
pool.</param>
/// <param name="collection">The collection used to store the elements of the pool.</param>
public ObjectPool(Func<T> generator, IProducerConsumerCollection<T> collection)
: base(collection)
{
if (generator == null) throw new ArgumentNullException("generator");
_generator = generator;
}
/// <summary>Adds the provided item into the pool.</summary>
/// <param name="item">The item to be added.</param>
public void PutObject(T item) { base.TryAdd(item); }
/// <summary>Gets an item from the pool.</summary>
/// <returns>The removed or created item.</returns>
/// <remarks>If the pool is empty, a new item will be created and returned.</remarks>
public T GetObject()
{
T value;
return base.TryTake(out value) ? value : _generator();
}
/// <summary>Clears the object pool, returning all of the data that was in the pool.</summary>
/// <returns>An array containing all of the elements in the pool.</returns>
public T[] ToArrayAndClear()
{
var items = new List<T>();
T value;
while (base.TryTake(out value)) items.Add(value);
return items.ToArray();
}
protected override boolTryAdd(T item)
{
PutObject(item);
return true;
}
protected override boolTryTake(out T item)
{
item = GetObject();
return true;
}
}
}
/// <summary>
/// Provides a base implementation for producer-consumer collections that wrap other
/// producer-consumer collections.
/// </summary>
/// <typeparam name="T">Specifies the type of elements in the collection.</typeparam>
[Serializable]
public abstract class ProducerConsumerCollectionBase<T> : IProducerConsumerCollection<T>
{
private readonlyIProducerConsumerCollection<T> _contained;
/// <summary>Initializes the ProducerConsumerCollectionBase instance.</summary>
/// <param name="contained">The collection to be wrapped by this instance.</param>
protected ProducerConsumerCollectionBase(IProducerConsumerCollection<T> contained)
{
if (contained == null) throw new ArgumentNullException("contained");
_contained = contained;
}
/// <summary>Gets the contained collection.</summary>
protected IProducerConsumerCollection<T>ContainedCollection { get { return _contained; } }
/// <summary>Attempts to add the specified value to the end of the deque.</summary>
/// <param name="item">The item to add.</param>
/// <returns>true if the item could be added; otherwise, false.</returns>
protected virtual boolTryAdd(T item) { return _contained.TryAdd(item); }
/// <summary>Attempts to remove and return an item from the collection.</summary>
/// <param name="item">
/// When this method returns, if the operation was successful, item contains the item removed. If
/// no item was available to be removed, the value is unspecified.
/// </param>
/// <returns>
/// true if an element was removed and returned from the collection; otherwise, false.
/// </returns>
protected virtual boolTryTake(out T item) { return _contained.TryTake(out item); }
/// <summary>Attempts to add the specified value to the end of the deque.</summary>
/// <param name="item">The item to add.</param>
/// <returns>true if the item could be added; otherwise, false.</returns>
boolIProducerConsumerCollection<T>.TryAdd(T item) { return TryAdd(item); }
/// <summary>Attempts to remove and return an item from the collection.</summary>
/// <param name="item">
/// When this method returns, if the operation was successful, item contains the item removed. If
/// no item was available to be removed, the value is unspecified.
/// </param>
/// <returns>
/// true if an element was removed and returned from the collection; otherwise, false.
/// </returns>
boolIProducerConsumerCollection<T>.TryTake(out T item) { return TryTake(out item); }
/// <summary>Gets the number of elements contained in the collection.</summary>
public int Count { get { return _contained.Count; } }
/// <summary>Creates an array containing the contents of the collection.</summary>
/// <returns>The array.</returns>
public T[] ToArray() { return _contained.ToArray(); }
/// <summary>Copies the contents of the collection to an array.</summary>
/// <param name="array">The array to which the data should be copied.</param>
/// <param name="index">The starting index at which data should be copied.</param>
public void CopyTo(T[] array, int index) { _contained.CopyTo(array, index); }
/// <summary>Copies the contents of the collection to an array.</summary>
/// <param name="array">The array to which the data should be copied.</param>
/// <param name="index">The starting index at which data should be copied.</param>
void ICollection.CopyTo(Array array, int index) { _contained.CopyTo(array, index); }
/// <summary>Gets an enumerator for the collection.</summary>
/// <returns>An enumerator.</returns>
public IEnumerator<T>GetEnumerator() { return _contained.GetEnumerator(); }
/// <summary>Gets an enumerator for the collection.</summary>
/// <returns>An enumerator.</returns>
IEnumeratorIEnumerable.GetEnumerator() { return GetEnumerator(); }
/// <summary>Gets whether the collection is synchronized.</summary>
boolICollection.IsSynchronized { get { return _contained.IsSynchronized; } }
/// <summary>Gets the synchronization root object for the collection.</summary>
object ICollection.SyncRoot { get { return _contained.SyncRoot; } }
9. Agent based object pool
25 Lines of code
1Type alias
2Types
F#
25 Lines 689 Characters
59% less Lines
66% less Characters
C#
61 Lines 2041 Characters
2.4x more Lines
2.96x more Characters
functions
modulePoc
//Agent alias for MailboxProcessor
typeAgent<'T>=MailboxProcessor<'T>
///One of three messages for our Object Pool agent
typePoolMessage<'a>=
| GetofAsyncReplyChannel<'a>
| Putof'a
| ClearofAsyncReplyChannel<List<'a>>
/// Object pool representing a reusable pool of objects
typeObjectPool<'a>(generate:unit->'a, initialPoolCount) =
letinitial=List.initinitialPoolCount (fun (x) ->generate())
letagent=Agent.Start(funinbox->
letrecloop(x) =async {
let!msg=inbox.Receive()
matchmsgwith
| Get(reply) ->
letres=matchxwith
| a::b->reply.Reply(a);b
| [] asempty->reply.Reply(generate());empty
return!loop(res)
| Put(value)->return!loop(value::x)
| Clear(reply) ->
reply.Reply(x)
return!loop(List.empty<'a>) }
loop(initial))
/// Clears the object pool, returning all of the data that was in the pool.
memberthis.ToListAndClear() =agent.PostAndAsyncReply(Clear)
/// Puts an item into the pool
memberthis.Put(item ) =agent.Post(item)
/// Gets an item from the pool or if there are none present use the generator
memberthis.Get(item) =agent.PostAndAsyncReply(Get)
10. F# open source project - FractureIO
High performance networking
Composable pipeline library
Agent based infrastructure
Notas del editor
Credit Suisse – rapid development or modelsGrange Insurance - order of magnitude speed increase, running what if scenarios, parrellismEon Energy Trading – pluggable calculation enginesXbox live – Multi-Terrabyte parsing and analytics