fp day 2011 - turning to the functional side (using c# & f#)
DESCRIPTION
Slides presented at FP Day 2011 in CambridgeTRANSCRIPT
Turning to the Functional side(Using C# and F#)
Phil Trelfordhttp://trelford.com/blog
@ptrelford
Tomas Petricekhttp://tomasp.net/blog
@tomaspetricek
About Us
» Tomas • Author of F# book for C# programmers• Worked with the F# team at Microsoft• First blogged about F# in May 2006
» Phil• Software Developer and Architect• Worked on first F# applications at Microsoft• Co-organizer of London F# User Group
» http://functional-programming.net
Tutorial
Goals
» Introduce Functional Concepts with F# and C#
Non-goals
» Provide in-depth understanding
» Mass conversion to functional programming cult
» Sell books
Thoughtworks Technology Radar July 2011
Visual F#
The F in F# stands for FUN
Halo 3 with F# Skills
XBLA: Path to Go – F# AI
F#
» Strongly Typed
» Functional
» Object Orientated
» Open Source
» .Net language
» In Visual Studio
Functional Programing
» Pure Functions
» Higher Order Functions
» Pattern Matching
Pure Functions - Excel
Higher Order Functions
let map f xs = seq {
for x in xs do
yield f x
}
let reduce f init items =
let mutable current = init
for item in items do
current <- f current item
current
F# Map/Reduce C# Map/Reduce
public static
IEnumerable<R> Map<T, R>
(this IEnumerable<T> xs,
Func<T, R> f)
{
foreach (var x in xs)
yield return f(x);
}
public static R
Reduce<T, R>
(this IEnumerable<T> xs,
R init,
Func<R, T, R> f)
{
var current = init;
foreach (var x in xs)
current = f(current, x);
return current;
}
Pattern Matching
match day with
| 0 -> "Sunday"
| 1 -> "Monday"
| 2 -> "Tuesday"
| 3 -> "Wednesday"
| 4 -> "Thursday"
| 5 -> "Friday"
| 6 -> "Saturday"
| _ –>
invalidArg "Invalid day"
F# C#
switch (day) {
case 0: return "Sunday";
case 1: return "Monday";
case 2: return "Tuesday";
case 3: return "Wednesday";
case 4: return "Thursday";
case 5: return "Friday";
case 6: return "Saturday";
default:
throw new
ArgumentException("day");
}
Light Syntax
type Person(name:string,age:int) =
/// Full name
member person.Name = name
/// Age in years
member person.Age = age
F# C#public class Person
{
public Person(string name, int age)
{
_name = name;
_age = age;
}
private readonly string _name;
private readonly int _age;
/// <summary>
/// Full name
/// </summary>
public string Name
{
get { return _name; }
}
/// <summary>
/// Age in years
/// </summary>
public int Age
{
get { return _age; }
}
}
Functional data structures
» A way of thinking about problems
» Model data using composition of primitives
Combine two values of different typesTuple
Represents one of several optionsDiscriminated
Union
Zero or more values of the same typeList
Tuples: Containers for a few different things
Discriminated Unions: Exclusive alternatives
Representing event schedule
Object-oriented way
» Easy to add new cases» Hard to add new functions
Functional way
» Easy to add new functions» Hard to add new cases
GetNextOccurrence() : DateTime
Schedule
Never RepeatedlyOnce
Tag : ScheduleType
Schedule
Never RepeatedlyOnce
» Good thing about F# and Scala – you can use both!
Cutting the caterpillar
Head
Head
Head
Head
Head
End!
Functional Lists in C#
» List is either empty or nonempty
• In C#, a class hierarchy with two classes• In F#, a discriminated union with two cases
List
EmptyNonempty(head, tail)
Functional lists in C#
public class FunctionalList<T> { // Creates a new list that is empty public FunctionalList(); // Creates a non-empty list public FunctionalList(T head, FunctionalList<T> tail);
// Is the list empty? public bool IsEmpty { get; }
// Properties valid for a non-empty list public T Head { get; } public FunctionalList<T> Tail { get; }}
Domain Modelling
» Retail Domain -> Testing
» http://tomasp.net/fpday.zip
Processing Stock Prices
Yahoo Stock Prices
» Data stored in a CSV file
» Read and print all data
Date,Open,High,Low,Close,Volume,Adj Close2011-10-12,407.34,409.25,400.14,402.19,22206600,402.192011-10-11,392.57,403.18,391.50,400.29,21609800,400.292011-10-10,379.09,388.81,378.21,388.81,15769200,388.81
open System.IO
let dir = __SOURCE_DIRECTORY__ + "\\data\\aapl.csv"let lines = File.ReadAllLines(dir)for line in lines do printfn "%s" line
Parsing CSV data
» Get some data for testing
» Using arrays in F#
» Converting strings to numbers
let line1 = lines |> Seq.headlet line2 = lines |> Seq.skip 1 |> Seq.head
let arr = str.Split([| ',' |])arr.[0]
float "12.34"DateTime.Parse("1985-05-02")
Iterate over lines, parse CSV and print date & price
TASK #1
Sequence expressions
» Exploring data using imperative loops
» Can be turned into a sequence expression…
• Result has a type seq<int * float> (IEnumerable)• Brackets: [| … |] for arrays, [ … ] for lists, set [ … ] for sets
for year, value in yearlyAverages do if value < 25.0 then printfn "%d (only %f)" year value
let badYears = seq { for year, value in yearlyAverages do if value < 25.0 then yield year, value }
Turn the parsing into a sequence expression
TASK #2
Organizing Source Code
» Compiled Libraries• Allow C# users call F# code• Encapsulate (complete) functionality
» F# Script Files• Great for explorative programming• Script can load some other files
// File1.fsxmodule StockData
let getData name = name, 99.0
// File2.fsx#load "File1.fsx"open StockData
getData "MSFT"
Write function that parses specified CSV file
TASK #3
Processing Data in F#
» Writing data processing query in F#
» Seq module provides functions for IEnumerable• But some operations make only sense for arrays/lists
» Sequence expressions provide query-like syntax
StockData.MSFT |> Seq.filter (fun stock -> stock.Close - stock.Open > 7.0)|> Seq.map (fun stock -> stock.Date)|> Seq.iter (printfn "%A")
Lambda function
Partial function applicationCustom
operators
All types are inferred
Useful functions
» Basic Functions• Seq.filter – filter elements using predicate (aka Where) • Seq.map – turn values into different (aka Select)
» Aggregating all elements of a sequence• Seq.max, Seq.min, Seq.averag – the obvious• Seq.fold – general aggregation
» Grouping elements of a sequence• Seq.groupBy – group using key• Seq.pairwise – adjacent pairs• Seq.windowed – sliding window
» For more see: http://fssnip.net/categories/Sequences
Calculate standard deviation of the data
TASK #5
√∑ (𝑣 𝑖−𝑎𝑣𝑔)2
𝑐𝑜𝑢𝑛𝑡
Find number of days when closing price is larger than opening price by more than $5.
TASK #4
FSharpChart library
» Easy to use charting library for F#• Based on .NET 4.0 Chart Controls (WinForms/ASP.NET)
» Designed to fit nicely with F#
[ for st in StockData.MSFT -> st.Date, st.Open ]|> FSharpChart.Line
Light-weight syntax for projections
Line chart expects value or key *
value
[ for st in StockData.MSFT -> st.Date, st.Open ]|> FSharpChart.Line|> FSharpChart.WithTitle ( Text = "Microsoft Stock Prices", Font = new System.Drawing.Font("Calibri", 16.0f) )
Create chart that shows values with 5 day average.This can be done using Seq.windowed
TASK #6
Create chart that shows prices together with standard deviation (over 5 day window) range
TASK #7
» Observable• Source generates data
(push-based model)• Process data on-the-fly• F# libs and .NET Rx
» Parallel Sequence• Parallel implementation• Process large amount
of in-memory data• Available in F# PowerPack
prices |> Seq.windowed 100 |> PSeq.ordered |> PSeq.map averageAndSdv
pricesEvent |> Observable.windowed 100 |> Observable.map averageAndSdv
In-memory, but processed in
parallel
Processing live data on
the fly
Processing data live and in parallel
Async Programming
The Problem
» Problems with I/O bound computations• Avoid blocking user interface• Handle many requests concurrently
» What needs to be done differently?• Avoid creating and blocking too many threads• Reliability and scalability are essential• React to events (from I/O or even GUI)
Using Explicit Callbacks
» Event-based programming model
• Callback called when operation completes• Gaining popularity (e.g. Node.js)
» Does not solve all problems• Control structures don’t work (loops, try-catch, …)• Difficult to work with state
HttpServer.Start("http://localhost:8080/", fun ctx -> WebClient.DownloadAsync(getProxyUrl(ctx), fun data -> ctx.ResponseStream.WriteAsync(data, fun res -> ctx.ResponseStream.Close())))
Synchronous to Asynchronous
» What would we want to write?
» Turning synchronous to asynchronous• Wrap body in an async block• Asynchronous calls using do! and let! • Supports all F# control flow constructs
let copyPageTo url outputStream = try let html = WebClient.AsyncDownload(url) outputStream.AsyncWrite(html) finally ctx.ResponseStream.Close()
let copyPageTo url outputStream = async { try let! html = WebClient.AsyncDownload(url) do! outputStream.AsyncWrite(html) finally ctx.ResponseStream.Close() }
Async User Interfaces
Async GUI programming
» Controlling semaphore light• Using int or enum to keep current state?• Difficult to read – what does state represent?
» Better approach – asynchronous waiting• Loop switches between state• Asynchronous waiting for events
green orange red
Writing loops using workflows
» Using standard language constructs
» Key idea – asynchronous waiting• F# events are first class values• Can use functional & imperative style
let semaphoreStates() = async { while true do for current in [ green; orange; red ] do let! md = Async.AwaitEvent(this.MouseDown) display(current) }
Infinite loop!
Wait for click
Checkout application workflow
» Think of a simple while loop
Print summary
Scan items
Complete purchaseNext customer
Startup
Asynchronous and concurrent programming
» Asynchronous GUI in Checkout example• Single-threaded thanks to Async.StartImmediate• Easy way to encode control flow
» Parallel programming• Workflows are non-blocking computations• Run workflows in parallel with Async.Parallel
» Concurrent programming• Compose application from (thousands of) agents• Agents communicate using messages
Summary
» FP is already in the mainstream
» FP languages are ready
» Start small, go big• Language Orientated Programming• Exploratory and Scripting• Asynchronous & Concurrency• Technical Computing• Testing
Summary
Don’t underestimate the power of the
functional side
ICFP 2011
Meet the F#ers
@rickasaurus
@tomaspetricek
@dmohl
F# Books
» http://functional-programming.net
On the horizon
http://meetup.com/fsharplondonEvery 6 weeks @ Skills Matter
Q & A
» http://Fsharp.net
» http://fssnip.net
» http://tomasp.net/blog
» http://trelford.com/blog