Transcript
Page 1: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Taking Functional Programming into the MainstreamDon Syme, Principal ResearcherMicrosoft Research, Cambridge

Page 2: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Disclaimer

• I’m a Microsoft Guy. I’m a .NET Fan. I will be using Visual Studio in this talk.

• This talk is offered in a spirit of cooperation and idea exchange. Please accept it as such

Page 3: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Topics

• Why is Microsoft Investing in Functional Programming?

• Some Simple F# Programming

• A Taste of Parallel/Reactive with F#

• An Announcement

Page 4: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Why is Microsoft investing in Functional Programming?

Page 5: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

What Investments?

• C# (Generics, LINQ)• F#• Reactive Framework• Haskell• VB, Python, Ruby

Page 6: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Simplicity

Page 7: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Economics

Page 8: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Fun, Fun and More Fun!

Page 9: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Simplicity

Page 10: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Code!

//F#open Systemlet a = 2Console.WriteLine a

//C#using System;

namespace ConsoleApplication1{ class Program { static int a() { return 2; } static void Main(string[] args) { Console.WriteLine(a);

} }}

More Noise Than Signal!

Page 11: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Pleasure type Command = Command of (Rover -> unit)

let BreakCommand     = Command(fun rover -> rover.Accelerate(-1.0))

let TurnLeftCommand  = Command(fun rover -> rover.Rotate(-5.0<degs>)) 

Pain   abstract class Command    {        public virtual void Execute();    }    abstract class MarsRoverCommand : Command    {        protected MarsRover Rover { get; private set; }         public MarsRoverCommand(MarsRover rover)        {            this.Rover = rover;        }    }    class BreakCommand : MarsRoverCommand    {        public BreakCommand(MarsRover rover)            : base(rover)        {        }         public override void Execute()        {            Rover.Rotate(-5.0);        }    } class TurnLeftCommand : MarsRoverCommand    {        public TurnLeftCommand(MarsRover rover)            : base(rover)        {        }        public override void Execute()        {            Rover.Rotate(-5.0);        }    }

Page 12: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Pleasure

let swap (x, y) = (y, x)

let rotations (x, y, z) = [ (x, y, z); (z, x, y); (y, z, x) ]

let reduce f (x, y, z) = f x + f y + f z

Pain

Tuple<U,T> Swap<T,U>(Tuple<T,U> t){ return new Tuple<U,T>(t.Item2, t.Item1)}

ReadOnlyCollection<Tuple<T,T,T>> Rotations<T>(Tuple<T,T,T> t)

{ new ReadOnlyCollection<int> (new Tuple<T,T,T>[] { new

Tuple<T,T,T>(t.Item1,t.Item2,t.Item3); new

Tuple<T,T,T>(t.Item3,t.Item1,t.Item2); new

Tuple<T,T,T>(t.Item2,t.Item3,t.Item1); });}

int Reduce<T>(Func<T,int> f,Tuple<T,T,T> t) { return f(t.Item1) + f(t.Item2) + f

(t.Item3); }

Page 13: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Pleasuretype Expr =       | True       | And of Expr * Expr       | Nand of Expr * Expr       | Or of Expr * Expr       | Xor of Expr * Expr       | Not of Expr  

Painpublic abstract class Expr { }   public abstract class UnaryOp :Expr   {       public Expr First { get; private set

; }       public UnaryOp(Expr first)       {           this.First = first;       }   }     public abstract class BinExpr : Expr   {       public Expr First { get; private set

; }       public Expr Second { get; private se

t; }         public BinExpr(Expr first, Expr seco

nd)       {           this.First = first;           this.Second = second;       }   }     public class TrueExpr : Expr { }     public class And : BinExpr   {       public And(Expr first, Expr second) 

: base(first, second) { }   }public class Nand : BinExpr   {       public Nand(Expr first, Expr second)

 : base(first, second) { }   }     public class Or : BinExpr   {       public Or(Expr first, Expr second) :

 base(first, second) { }   }     public class Xor : BinExpr   {       public Xor(Expr first, Expr second) 

: base(first, second) { }   }     public class Not : UnaryOp   {       public Not(Expr first) : base(first)

 { }   }      

Page 14: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Economics

Page 15: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Fun, Fun and More Fun!

Page 16: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

YouCanInteroperateWithEverything

Page 17: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

EverythingCanInteroperateWithYou

Page 18: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F#: Influences

OCaml

C#/.NET

F#

Similar core language

Similar objectmodel

Page 19: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F#: Combining Paradigms

I've been coding in F# lately, for a production task.

F# allows you to move smoothly in your programming style... I start with pure functional code, shift slightly towards an object-oriented style, and in production code, I sometimes have to do some imperative programming.

I can start with a pure idea, and still finish my project with realistic code. You're never disappointed in any phase of the project!

Julien Laugel, Chief Software Architect, www.eurostocks.com

Page 20: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Let’s WebCrawl...

Page 21: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Orthogonal & Unified Constructs

• Let “let” simplify your life…

let data = (1, 2, 3)

let f (a, b, c) = let sum = a + b + c let g x = sum + x*x (g a, g b, g c)

Bind a static value

Bind a static function

Bind a local value

Bind a local function

Type inference. The safety of C# with the

succinctness of a scripting language

Page 22: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Quick Tour

Comments // comment

(* comment *)

/// XML doc commentlet x = 1

Page 23: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Quick Tour

Booleansnot expr Boolean negationexpr && expr Boolean “and”expr || expr Boolean “or”

Overloaded Arithmeticx + y Addition x - y Subtraction x * y Multiplication x / y Division x % y Remainder/modulus -x Unary negation

Page 24: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Fundamentals - Whitespace Matterslet computeDeriative f x = let p1 = f (x - 0.05)

let p2 = f (x + 0.05)

(p2 – p1) / 0.1

Offside (bad indentation)

Page 25: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Fundamentals - Whitespace Matterslet computeDeriative f x = let p1 = f (x - 0.05)

let p2 = f (x + 0.05)

(p2 – p1) / 0.1

Page 26: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Orthogonal & Unified Constructs

• Functions: like delegates + unified and simple

(fun x -> x + 1)

let f x = x + 1

(f, f)

val f : int -> int

Lambda

Declare afunction

A pair of function values

predicate = 'T -> bool

send = 'T -> unit

threadStart = unit -> unit

comparer = 'T -> 'T -> int

hasher = 'T -> int

equality = 'T -> 'T -> bool

One simple mechanism,

many uses

A function type

Page 27: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Functional– Pipelines

x |> f

The pipeline operator

Page 28: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Functional– Pipelines

x |> f1 |> f2 |> f3

Successive stages in a pipeline

Page 29: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Functional – Pipelining

open System.IO

let files = Directory.GetFiles(@"c:\", "*.*", SearchOption.AllDirectories)

let totalSize = files |> Array.map (fun file -> FileInfo file) |> Array.map (fun info -> info.Length) |> Array.sum

Sum of file sizes

Page 30: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Immutability the norm…

Values may not be

changed

Data is immutable by

default

Not Mutate

Copy & Update

Page 31: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

In Praise of Immutability

• Immutable objects can be relied upon

• Immutable objects can transfer between threads

• Immutable objects can be aliased safely

• Immutable objects lead to (different) optimization opportunities

Page 32: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Functional Data – Generating Structured Data

type Suit = | Heart | Diamond | Spade | Club type PlayingCard = | Ace of Suit | King of Suit | Queen of Suit | Jack of Suit | ValueCard of int * Suit 

Union type (no data =

enum)

Union type with data

Page 33: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Functional Data – Generating Structured Data (2)

let suits = [ Heart; Diamond; Spade; Club ] let deckOfCards = [ for suit in suits do yield Ace suit yield King suit yield Queen suit yield Jack suit for value in 2 .. 10 do yield ValueCard (value, suit) ] 

Generate a deck

of cards

Page 34: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

//F##lightopen Systemlet a = 2Console.WriteLine(a)

//C#using System;

namespace ConsoleApplication1{ class Program { static int a() { return 2; }

static void Main(string[] args)

{ Console.WriteLine(a);

} }}

Looks Weakly typed?

Maybe Dynamic?

Weakly Typed? Slow?

Page 35: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Typed Untyped

EfficientInterpretedReflection

Invoke

F#Yet rich, dynamic

Yet succinct

Page 36: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

What is Functional Programming?

• “Working with immutable data”• “A language with queries”• “A language with lambdas” • “A language with pattern matching”• “A language with a lighter syntax”• “Taming side effects”

“Anything but imperative

programming”???

Page 37: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Some Micro Trends

• Communication With Immutable Data

• Programming With Queries• Programming With Lambdas• Programming With Pattern Matching• Languages with a Lighter Syntax• Taming Side Effects

REST, HTML, XML, JSON, Haskell, F#, Scala, Clojure, Erlang,...

C#, VB, F#, SQL,

Kx....

C#, F#, Javascript,

Scala, Clojure

F#, Scala, ...

Python, Ruby, F#, ...

Erlang, Scala, F#, Haskell, ...

Page 38: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

The Huge Trends

THE WEB MULTICORE

Page 39: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F# Objects

Page 40: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F# - Objects + Functional

type Vector2D (dx:double, dy:double) =

member v.DX = dx member v.DY = dy member v.Length = sqrt (dx*dx+dy*dy) member v.Scale (k) = Vector2D (dx*k,dy*k)

Inputs to object

construction

Exported properties

Exported method

Page 41: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F# - Objects + Functional

type Vector2D(dx:double,dy:double) =

let norm2 = dx*dx+dy*dy

member v.DX = dx member v.DY = dy member v.Length = sqrt(norm2) member v.Norm2 = norm2

Internal (pre-computed) values and functions

Page 42: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F# - Objects + Functional

type HuffmanEncoding(freq:seq<char*int>) = ... < 50 lines of beautiful functional code> ...

member x.Encode(input: seq<char>) = encode(input) member x.Decode(input: seq<char>) = decode(input)

Immutable inputs

Internal tables

Publish access

Page 43: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F# - Objects + Functional

type Vector2D(dx:double,dy:double) =

let mutable currDX = dx

let mutable currDX = dy

member v.DX = currDX member v.DY = currDY member v.Move(x,y) = currDX <- currDX+x currDY <- currDY+y

Internal state

Publish internal

state

Mutate internal

state

Page 44: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

OO andFunctionalCanMix

Page 45: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Interlude: Case Study

Page 46: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

The adCenter Problem

Page 47: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

The Scale of Things

• Weeks of data in training: N,000,000,000 impressions, 6TB data

• 2 weeks of CPU time during training: 2 wks × 7 days × 86,400 sec/day =

1,209,600 seconds• Learning algorithm speed requirement:

• N,000 impression updates / sec• N00.0 μs per impression update

Page 48: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F# and adCenter

• 4 week project, 4 machine learning experts

• 100million probabilistic variables

• Processes 6TB of training data

• Real time processing

Page 49: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

AdPredict: What We Observed

• Quick Coding

• Agile Coding

• Scripting

• Performance

• Memory-Faithful

• Succinct

• Symbolic

• .NET Integration

F#’s powerful type inference means less typing, more

thinking

Type-inferred code is easily refactored

“Hands-on” exploration.

Immediate scaling to massive data

setsmega-data

structures, 16GB machines

Live in the domain, not the language

Schema compilation and

“Schedules”Especially Excel, SQL Server

Page 50: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Smooth Transitions

• Researcher’s Brain Realistic, Efficient Code

• Realistic, Efficient Code Component

• Component Deployment

Late 2009 Update... now part of Bing’s “sauce” for advertisers

Page 51: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F# Async/Parallel

Page 52: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

F# is a Parallel Language

(Multiple active computations)

F# is a Reactive Language

(Multiple pending reactions)

e.g. GUI Event Page Load

Timer CallbackQuery ResponseHTTP Response

Web Service ResponseDisk I/O

CompletionAgent Gets Message

Page 53: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

async { ... }

• For users: You can run it, but it may take a while

Or, your builder says...

OK, I can do the job, but I might have to talk to someone else about it. I’ll get back to you when I’m done

async { ... }

A Building Block for Writing Reactive Code

Page 54: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

async { ... }

async.Delay(fun () -> async.Bind(ReadAsync "cat.jpg", (fun image -> let image2 = f image async.Bind(writeAsync "dog.jpg",(fun () -> printfn "done!" async.Return())))))

async { let! image = ReadAsync "cat.jpg" let image2 = f image do! WriteAsync image2 "dog.jpg" do printfn "done!" return image2 }

Continuation/Event callback

Asynchronous "non-blocking"

action

You're actually writing this (approximately):

Page 55: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Code: Web Translation

Page 56: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Typical F# Reactive Architecture

Single Threaded GUI

Or

Single Threaded Page Handler

Or

Command Line Driver

Async.Parallel [ ... ]

new Agent<_>(async { ... })

new WebCrawler<_>() Internally: new Agent<_>(...) ...

event x.Started event x.CrawledPage event x.Finished

...

Async.Start (async { ... }

(queued)

Page 57: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Taming Asynchronous I/O

using System;using System.IO;using System.Threading; public class BulkImageProcAsync{    public const String ImageBaseName = "tmpImage-";    public const int numImages = 200;    public const int numPixels = 512 * 512;     // ProcessImage has a simple O(N) loop, and you can vary the number    // of times you repeat that loop to make the application more CPU-    // bound or more IO-bound.    public static int processImageRepeats = 20;     // Threads must decrement NumImagesToFinish, and protect    // their access to it through a mutex.    public static int NumImagesToFinish = numImages;    public static Object[] NumImagesMutex = new Object[0];    // WaitObject is signalled when all image processing is done.    public static Object[] WaitObject = new Object[0];    public class ImageStateObject    {        public byte[] pixels;        public int imageNum;        public FileStream fs;    }  

    public static void ReadInImageCallback(IAsyncResult asyncResult)    {        ImageStateObject state = (ImageStateObject)asyncResult.AsyncState;        Stream stream = state.fs;        int bytesRead = stream.EndRead(asyncResult);        if (bytesRead != numPixels)            throw new Exception(String.Format                ("In ReadInImageCallback, got the wrong number of " +                "bytes from the image: {0}.", bytesRead));        ProcessImage(state.pixels, state.imageNum);        stream.Close();         // Now write out the image.          // Using asynchronous I/O here appears not to be best practice.        // It ends up swamping the threadpool, because the threadpool        // threads are blocked on I/O requests that were just queued to        // the threadpool.         FileStream fs = new FileStream(ImageBaseName + state.imageNum +            ".done", FileMode.Create, FileAccess.Write, FileShare.None,            4096, false);        fs.Write(state.pixels, 0, numPixels);        fs.Close();         // This application model uses too much memory.        // Releasing memory as soon as possible is a good idea,         // especially global state.        state.pixels = null;        fs = null;        // Record that an image is finished now.        lock (NumImagesMutex)        {            NumImagesToFinish--;            if (NumImagesToFinish == 0)            {                Monitor.Enter(WaitObject);                Monitor.Pulse(WaitObject);                Monitor.Exit(WaitObject);            }        }    }

        public static void ProcessImagesInBulk()    {        Console.WriteLine("Processing images...  ");        long t0 = Environment.TickCount;        NumImagesToFinish = numImages;        AsyncCallback readImageCallback = new            AsyncCallback(ReadInImageCallback);        for (int i = 0; i < numImages; i++)        {            ImageStateObject state = new ImageStateObject();            state.pixels = new byte[numPixels];            state.imageNum = i;            // Very large items are read only once, so you can make the             // buffer on the FileStream very small to save memory.            FileStream fs = new FileStream(ImageBaseName + i + ".tmp",                FileMode.Open, FileAccess.Read, FileShare.Read, 1, true);            state.fs = fs;            fs.BeginRead(state.pixels, 0, numPixels, readImageCallback,                state);        }         // Determine whether all images are done being processed.          // If not, block until all are finished.        bool mustBlock = false;        lock (NumImagesMutex)        {            if (NumImagesToFinish > 0)                mustBlock = true;        }        if (mustBlock)        {            Console.WriteLine("All worker threads are queued. " +                " Blocking until they complete. numLeft: {0}",                NumImagesToFinish);            Monitor.Enter(WaitObject);            Monitor.Wait(WaitObject);            Monitor.Exit(WaitObject);        }        long t1 = Environment.TickCount;        Console.WriteLine("Total time processing images: {0}ms",            (t1 - t0));    }}

let ProcessImageAsync () = async { let inStream = File.OpenRead(sprintf "Image%d.tmp" i) let! pixels = inStream.ReadAsync(numPixels) let pixels' = TransformImage(pixels,i) let outStream = File.OpenWrite(sprintf "Image%d.done" i) do! outStream.WriteAsync(pixels') do Console.WriteLine "done!" } let ProcessImagesAsyncWorkflow() = Async.Run (Async.Parallel [ for i in 1 .. numImages -> ProcessImageAsync i ]) 

Processing 200 images in parallel

Page 58: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Units of Measure

Page 59: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

let EarthMass = 5.9736e24<kg>

// Average between pole and equator radiilet EarthRadius = 6371.0e3<m>

// Gravitational acceleration on surface of Earth let g = PhysicalConstants.G * EarthMass / (EarthRadius * EarthRadius)

Page 60: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Microsoft + Eclipse Interoperability

For Vijay RajagopalanMicrosoft Interoperability Team

Page 61: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

•Enh

anc

e

Ecli

pse

dev

elop

er

exp

erie

nce

on

Win

dow

s 7

Eclipse on Windows 7

•Plu

g-in

for

Ecli

pse

to

buil

d

Silv

erli

ght

Rich

Inte

rnet

App

licat

ions

Eclipse Tools for

Silverlight

•Ena

ble

PHP

,

Java

dev

elop

ers

usin

g

Ecli

pse

to

buil

d &

depl

oy

on

Azu

re

Windows Azure +

Eclipse / PHP

Announcing: Projects fostering interoperability between Eclipse and Microsoft’s platform

Page 62: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

8 Ways to Learn Functional Programming

• F# + FSI.exe

• F# + Reflector

• Haskell

• Clojure

• http://cs.hubfs.net

• Scala

• C# 3.0

• ML

Page 63: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Books about F#

Visit www.fsharp.net

Page 64: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Books about F#

Visit www.fsharp.net

Page 65: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

Questions

Page 66: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

The many uses of async { ... }

• Sequencing CPU computations

• Sequencing I/O requests

async { let result1 = fib 39 let result2 = fib 40 return result1 + result2 }

async { let! lang = CallDetectLanguageService text let! text2 = CallTranslateTextService (lang, "da", text) return text2 }

Page 67: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

The many uses of async { ... }

• Parallel CPU computations

• Parallel I/O requests

Async.Parallel [ async { return fib 39 }; async { return fib 40 }; ]

Async.Parallel [ for targetLang in languages -> translate (text, language) ]

Page 68: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

The many uses of async { ... }

• Sequencing CPU computations and I/O requestsasync { let! lang = callDetectLanguageService text

let! text2 = callTranslateTextService (lang, "da", text) let text3 = postProcess text return text3 }

Page 69: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

The many uses of async { ... }

• Repeating tasks

• Repeating tasks with state

async { while true do let! msg = queue.ReadMessage() <process message> }

let rec loop count = async { let! msg = queue.ReadMessage() printfn "got a message" return! loop (count + msg) }

loop 0

let rec loop () = async { let! msg = queue.ReadMessage() printfn "got a message" return! loop () }loop ()

Page 70: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

The many uses of async { ... }

• Representing Agents (approximate) let queue = new Queue()

let rec loop count = async { let! msg = queue.ReadMessage() printfn "got a message" return! loop (count + msg) } Async.Start (loop 0)

queue.Enqueue 3queue.Enqueue 4

Page 71: Taking Functional Programming Into The Mainstream - Eclipse Summit Europe 2009

The many uses of async { ... }

• Representing Agents (real) let agent = Agent.Start( let rec loop count = async { let! msg = queue.ReadMessage() printfn "got a message" return! loop (count + msg) } loop 0)

agent.Post 3agent.Post 4Note:

type Agent<'T> = MailboxProcessor<'T>


Recommended