qcon2011 functions rockpresentation_f_sharp
DESCRIPTION
This is the talk i planned at QCon 2011 on FSharp. It is part II of a half-full day tutorial. (The first part is covering Scala).TRANSCRIPT
© Prof. Dr. Michael Stal, 2011
Functions rock!Harnessing the Power of Functional Part II: Programming with F#TUTORIAL
QCON 2011, London
Prof. Dr. Michael Stal
© Prof. Dr. Michael Stal, 2011
Objectives of Presentation
Introducing core concepts of Functional Programming
Introducing F# as example Presenting the benefits of
combining OO and functional programming
Illustrating the language in a pragmatic way preferring code over theory
But not to cover every available aspect or to cover aspects in full detail
Page 2
© Prof. Dr. Michael Stal, 2011
What is Functional Programming?
Praise the Lambda Calculus (which is almost 80 years old) and its successors (e.g., the typed ones)
(Mathematical) Functions Are a means of decomposition Can be assigned to variables Can be passed as arguments to
or returned from functions Can be anonymous (closures)
Emphasize on Immutability: No side-effects of functions
(referential transparency) Values instead of variables
Page 3
© Prof. Dr. Michael Stal, 2011
Functional Programming Languages …
Are often hybrid such as Lisp/Clojure, F#, Scala
Use Recursion instead of Iteration
Can be strict (eager) or non-strict (lazy)
Use mainly the Typed Lambda Calculus and thus support Pattern Matching
Support concepts such as Monads, Continuations
Integrate Comprehensions for collection types, Catamorphisms (fold), Anamorphisms (unfold)
Page 4
© Prof. Dr. Michael Stal, 2011
Preconception: Functional Languages are Slow
Is not true anymore due to: Highly efficient VMs like the
CLR, JVM Structural Sharing, no naive
copying Tail Call Optimization: at least
some VMs Very efficient and powerful
Libraries Easy leveraging of
Concurrency (e.g., because of immutablity)
Page 5
© Prof. Dr. Michael Stal, 2011
„Now for something completely different“ Introduction to F# 2.0
F# created by Don Syme at Microsoft Research, Cambridge, UK
Started at 2002; team also closely associated with introduction of Generics to CLR
F# combines Object Oriented Programming with Functional Programming
Page 6
Don Syme, Source: msdn.microsoft.com/en-us/fsharp/default
© Prof. Dr. Michael Stal, 2011
Core Properties of F#
F# is compatible: runs on CLR/Mono, interoperability with other CLR languages
F# is simple and compact: a very small language core with a flat learning curve
F# is succinct: More compact code, lower noise-to-signal ratio
F# is high-level: Higher level of abstraction by combining OO with functional programming
F# is statically typed: type inference gives F# the „look&feel“ of a dynamically typed language
Page 7
F#‘s Roots:• Haskell• ML• OCaml (similar core language) • C# (similar object
model)
© Prof. Dr. Michael Stal, 2011
A small Appetizer – taken from „Expert F#“!
Page 8
/// Split a string into words at spaceslet splitAtSpaces (text: string) = text.Split ' ' |> Array.toList/// Analyze a string for duplicate wordslet wordCount text = let words = splitAtSpaces text let wordSet = Set.ofList words let numWords = words.Length let numDups = words.Length - wordSet.Count (numWords,numDups)/// Analyze a string for duplicate words and display the results.let showWordCount text = let numWords,numDups = wordCount text printfn "--> %d words in the text" numWords printfn "--> %d duplicate words" numDupslet main = showWordCount "Hello, F# developer. As a developer you will have a lot of fun using F#"do main // => 15 words in the text <cr> 2 duplicate words
Functions
Immutable values
no semicolons
No brackets!
Type Inference
© Prof. Dr. Michael Stal, 2011
How to obtain F#
Source code file may be compiled using fsc: fsc myExample.fs which creates an executable for the CLR
You may run an interactive shell by using the following command line instead fsi In this case type the commands directly
into the shell using ;; as delimiters You might use Visual Studio 2008 and install
F# or Visual Studio 2010 (F# included!) You may use SharpDevelop and F# On Mac OS X, Linux:
install Mono, then F# for Mac und Linux add MonoDevelop and the F# Add-In if
you prefer an IDE
Page 9
For instructions on how to install F# on Mac, Linux:http://functional-variations.net/
© Prof. Dr. Michael Stal, 2011
Example: Using Visual Studio 2010
Page 10
Editor Window
F# Interactive
SolutionExplorer
© Prof. Dr. Michael Stal, 2011
F# in a Sandbox
URL: http://tryfs.net/
Page 11
© Prof. Dr. Michael Stal, 2011
F# Type System
Basic types from the .NET CLI plus classes, interfaces, generics
Function Types, Lambdas Tuples, Lists, Arrays Discriminated Unions Records and Structures Unit (equivalent to void in C++) Option (Monadic Type: Maybe
Monad) Delegates Attributes Exceptions
Page 12
bool, byte sbyte, int16, uint6,int, uint32, int64, uint64, char,nativeint, unativeint, string, decimal, unit, void, single,double
© Prof. Dr. Michael Stal, 2011
let it be
The let statement lets you define values Let‘s use the „REPL“ (actually not a REPL; F# is compiled on the fly)
Page 13
© Prof. Dr. Michael Stal, 2011
let for assigning values
Values may be reassigned Mind the difference: the old values are not overwritten, but the identifiers
refer to a new value!
Page 14
let x = 5// val x : int = 5let x = x + 5// val x : int = 10let x = x - 9// val x : int = 1
© Prof. Dr. Michael Stal, 2011
let for function definition
Using let for giving an anonymous function a name
The function definition can also be written as:
Page 15
let poly1 = fun x -> 2.0 * x * x - x + 1.0// => val poly1 float -> float
poly1 1.5// => val it : float = 4
A closure
let poly1 x = 2.0 * x *x - x + 1.0// => val poly1 float -> float
© Prof. Dr. Michael Stal, 2011
Using Closures in F#
Closures represent first-class functions that contain free variables
They bind free variables to their definition context
Page 16
let a = 42let g x f = f x printfn "%i" (g 12 (fun i -> a)) // => 42
// But we could also do something like:g 12 (printfn "%i") // => 12
Closure
binding
© Prof. Dr. Michael Stal, 2011
Specifying types is optional due to type inference
Type inference allows the compiler to automatically defer the types But you can also specify types explicitly
Page 17
let x : int = 12let l : int List = [1; 2; 3]let twice (x: float) = 2.0 * x
© Prof. Dr. Michael Stal, 2011
Special Types: unit
unit represents an expression or function with no value
Page 18
printfn "QCon 2011 rocks!";; QCon 2011 rocks!type is : val it : unit = ()
let printHello = printfn “Hello” type is : val printHello: unit = ()
© Prof. Dr. Michael Stal, 2011
Special Types: Option
Option is a monadic type (MayBe-Monad) for expressions that either return nothing or a result
Applicable to avoid dealing with alternative conditions
Page 19
let div a b = if (b = 0) then None else Some(a/b)
div 6 3 // => Some(2)div 6 0 // => None
© Prof. Dr. Michael Stal, 2011
let for recursive functions
defining a recursive function requires the keyword rec
Page 20
let rec fib n = if (n <= 1) then 1 else fib(n-1) + fib(n-2)(* fib 1 => 1 fib 2 => 2 fib 3 => 3 fib 4 => 5 fib 5 => 8*)
© Prof. Dr. Michael Stal, 2011
Mutual Recursion
defining mutual recursive functions
Page 21
let rec f1 x = if (x <= 1) then 1 else f2(x)and f2 x = if (x % 2 = 0) then f1(x/2) else f1(x/2 - 1)
printfn "%i" (f1 18) // => 1
© Prof. Dr. Michael Stal, 2011
Currying and Partial Function Application
F# supports partial function application:
Page 22
> let mult x y = x * y;;
val mult : int -> int -> int
> let double x = mult 2 x;;
val double : int -> int
> double 3;;val it : int = 6> double 4;;val it : int = 8
double is defined as partial application ofmult with first param 2
© Prof. Dr. Michael Stal, 2011
Lazy evaluations
F# supports lazy evaluations Lazy means: the value is only calculated on demand Powerful usage for collections (see later)
Page 23
let r = lazy ( let tmp = 2 * 21 printfn "Calculating" tmp )printfn "%d" (r.Force()) // => Calculating// Forced evaluation 42
© Prof. Dr. Michael Stal, 2011
Functions can be locally nested within functions
Note: In F# like in all functional languages there are no statements but
expressions Expressions always return values. The last value is used as the
result of the expression like sum(a,b,c) / 3 in the example:
Page 24
// using lightweight syntax: #lightlet avg (a,b,c) = let sum(a,b,c) = a + b + c sum(a,b,c) / 3let d = avg(1,2,3) printfn “and the average is %i” d // => 2
© Prof. Dr. Michael Stal, 2011
Operator Overloading in F#
It is possible to define/overload operators Code Example:
Page 25
let (*) a b = a + blet a = 2 * 7// => a = 9// may also be used in prefix notation:(*) 2 6 // => 8// for unary operators:let (~-) n = 1 – n- 88 // => -87
© Prof. Dr. Michael Stal, 2011
Exceptional F#
raise used to raise exception of appropriate exception type try/with and try/(with/)finally both available Exceptions can also be raised with: failsWith “Wrong input“
Page 26
exception EvenArgument of intlet printNumber n = if (n % 2 = 0) then raise (EvenArgument n) else printfn "%i" n
try printNumber 5 // ok printNumber 4 // => exception EvenArgument 4 with EvenArgument x -> printfn "Number %i is even!" x
© Prof. Dr. Michael Stal, 2011
The Pipeline Operator |>
The pipeline |> operator is very powerful let (|>) x f = f x // apply function f to x
There is also a <| operator (processing right to left) which is only seldomly used
The pipeline operator unfolds its real power with all the sophisticated collection types
Page 27
let x = sin 1.0// or:let x = 1.0 |> sin
© Prof. Dr. Michael Stal, 2011
Using Units of Measure
F# allows to assign units of measure Compiler checks for compatibility Remember: Some big aeronautics and space projects failed due to such
errors
Page 28
[<Measure>] type m // meter[<Measure>] type s // second// let a = 5.0<m> + 7.3<s> =>compiler errorlet distance = 100.0<m>let time = 5.0<s>let speed = (distance/time)let distanceInAnHour = speed * 3600.0<s>
© Prof. Dr. Michael Stal, 2011
Mutable F#
Use the keyword mutable for defining real variables The F# API also supports ref. This denotes a record which contains a
mutable element. Use ! to retrieve contained value and := to override Note: for some types mutable cousins exist
Page 29
> let mutable a = 41;;val mutable a : int = 41> a <- 42;;val it : unit = ()> a;;val it : int = 42> let i = ref(0);;val i : int ref = {contents = 0;}> i := !i + 42;;val it : unit = ()> !i;;val it : int = 42
© Prof. Dr. Michael Stal, 2011
Arrays
According to MSDN/F#: Arrays are fixed-size, zero-based, mutable collections of consecutive data elements that are all of the same type
Arrays can be created in several ways. Examples:
Page 30
// specifying the elementslet names = [| "Mick"; "Keith"; "Mark" |]
// sequence expressionslet squares = [| for i in 1..10 -> i * i |]
// initialized array: 10 elems with 0let ai : int array = Array.zeroCreate 10
// multidimensional 3 x 3 arraylet matrix : int array[,] = Array2D.zeroCreate 3 3
© Prof. Dr. Michael Stal, 2011
Basic Array Operations
Several basic operations are provided for arrays For example, operations to access parts of an array or operations to
create new arrays
Page 31
// get slicelet subarr = squares.[3..5]
// get element printfn "%d" ai.[2]
// modify elementai.[2] <- 6
© Prof. Dr. Michael Stal, 2011
Sophisticated Array operations
There are also lots of more sophisticated operations for arrays that are also available for other kinds of collections
Examples include fold, collect, concat, rev and more:
Page 32
let a1 = [|1; 2; 3|] let a2 = [|4; 5; 6 |]let a12 = Array.concat [a1; a2] // new array!
[| 1 .. 10 |] // array containing 1,2,3,..,10|> Array.filter (fun elem -> elem % 2 = 0) // even// for numbers n but 8 put Some(n * n) into array:|> Array.choose (fun elem -> if (elem <> 8) then Some(elem*elem) else None)|> Array.rev // revert sort order|> printfn "%A" //=> [|100; 36; 16; 4|]
© Prof. Dr. Michael Stal, 2011
Using Namespaces and Modules
Using the .NET Framework Classes is straightforward You may import namespaces using open Namespaces are defined in F# with namespace, modules with module Namespaces mustn‘t define values
Page 33
open System.Windows.Forms
let form = new Form (Visible=true, Text="QCon 2011")let button = new Button(Text ="Click me")button.Click.Add (fun _ -> printfn "Hello, London!")form.Controls.Add(button)form.BackColor <- System.Drawing.Color.AzureApplication.Run form
© Prof. Dr. Michael Stal, 2011
Modules
F# Modules can contain values, type definitions, submodules Modules are compiled as classes with static members
Page 34
module MathModule let rec hcf (a:bigint) (b:bigint) = if a = 0I then b elif (a < b) then hcf a (b-a) else hcf (a-b) b type Rational(a: bigint, b: bigint) = let n = hcf a b member r.a = a / n member r.b = b / n static member (+) r1 r2 = …
© Prof. Dr. Michael Stal, 2011
Implicit Generics
F# applies type inference for each definition If it cannot assign types it will treat the definition as a generic
definition with type parameters
In the example above the type parameter is 'a Let us instantiate the definition:
Page 35
> let makeList a b = [a; b]=> val makeList : 'a -> 'a -> 'a list
makeList 1 2=> val it : int list = [1; 2]
© Prof. Dr. Michael Stal, 2011
Explicit Generics
But you can also specify the types implicitly
Likewise, we can specify the type on usage
Page 36
let makeListExp<'T> (a : 'T) (b : 'T) = [a; b];;=> val makeListExp : 'T -> 'T -> 'T list
makeListExp<int> 1 2;;=> val it : int list = [1; 2]
© Prof. Dr. Michael Stal, 2011
Tuples
Tuples are very convenient for various applications
Page 37
let x = ( 1, 2) // val x : int * int = (1, 2)let a, b = x // val b : int = 2 // val a : int = 1let ad = ("Adam", 7) // val ad : string * int = ("Adam", 7)let swap (a,b) = (b,a) // val swap : 'a * 'b -> 'b * 'a
© Prof. Dr. Michael Stal, 2011
Sets
sets are used for various problems
Page 38
open System
let s : Set<int> = Set(seq{ 1..7 })let t = set[1;2;3]Console.WriteLine(s.Count)Console.WriteLine(s.MaximumElement)Console.WriteLine(s.IsProperSubsetOf(Set(seq{ 1..10 })))Console.WriteLine(s.IsProperSupersetOf(t))Console.WriteLine(s)let sl = Set.toList s // make a list
© Prof. Dr. Michael Stal, 2011
Maps
Maps (hash tables, dictionaries) are used as follows:
Page 39
let m = Map.empty .Add("Syme", "F#") .Add("Stroustrup", "C++") .Add("Gosling", "Java") .Add("McCarthy", "Lisp")
match m.TryFind("Syme") with | None -> printfn "not found" | Some(lng) -> printfn "%s" lng // F#Console.WriteLine(m.["McCarthy"]) // Lisp
© Prof. Dr. Michael Stal, 2011
Land of Lists
Lists are the core datatype of all functional languages F# provides excellent support for lists
Page 40
let l = [] // empty listlet l2 = "Hello" :: ", " :: l // add elements at the head let l3 = ["London"]let l4 = l2 @ l3 // concatenate two listslet l5 = l4 @ ["!";"!"] let l6 = List.rev l5 // reverse orderprintfn "%A" l5=> [“Hello”;”, “;”London”;”!”;”!”]
© Prof. Dr. Michael Stal, 2011
And even more on Lists
Several additional functions provided for lists
In addition, List contains many static members
Page 41
let lzip = List.zip [1; 2; 3] ['a';'b';'c']printfn "%A" lzip// => [(1, 'a'); (2, 'b'); (3, 'c')]let arr = List.toArray lzip // make array
let l = [ 'a'; 'b'; 'c'; 'd' ]printfn "%c" l.Head // => aprintfn "%A" l.Tail // => [‘b’;’c’;’d’]printfn "%d" l.Length // => 4
© Prof. Dr. Michael Stal, 2011
Pattern Matching
Pattern matching eases processing in functional languages It is applicable for all data types but is particularly valuable for
collections
Page 42
let rec addNumbers (l : 'int List) = match l with | [] -> 0 | head :: tail -> head + addNumbers tail
let l = [1; 2; 3; 4; 5]let sum = addNumbers lprintfn "%i" sum=> 15
© Prof. Dr. Michael Stal, 2011
Detour: General Pattern Matching
Pattern matching allows to analyze arguments for their value or type Appears to be a Java/C# switch on stereoids, but is much more
powerful, especially when dealing with collection types
The :? operator defines a dynamic type test Note there are also operators for static upcast (e.g., 1 :> obj ) and
dynamic downcast (e.g., shape :?> circle) in F#
Page 43
let reportObject (x: obj) = match x with | :? string as s -> printfn "string '%s'" s | :? int as d -> printfn "integer '%d'" d | :? float as f -> println “float ‘%f’” f | _ -> printfn “unknown"
© Prof. Dr. Michael Stal, 2011
Detour: General Pattern Matching using When clauses
when allows to further check an argument during pattern matching
Page 44
let i = -12
match i with | _ when i > 0 -> printfn "positive" | _ when i < 0 -> printfn "negative" | _ -> printfn "zero“
© Prof. Dr. Michael Stal, 2011
Detour: The wildcard _
In F# _ serves as a wildcard character Always used when you like to ignore parts of an expression
Another example: ignoring parameters
Page 45
match groups with | // pattern matching 1 | _ :: rest -> findFSharpUGs rest | [] -> printfn "end of list"
let apply f x = f xprintfn "%i" (apply (fun _ -> 42) 12)// => 42
© Prof. Dr. Michael Stal, 2011
Operations on Collections: map
There are several operations for collections that reveal the power of functional programming.
The most prominent example is map
Page 46
let l = [1; 2; 3; 4; 5]let l2 = List.map (fun x -> x * x) l
printfn "%A" l2 // => [1; 4; 9; 16; 25]
Apply the function (1st param)to all arguments of the list (2nd param)and create a new list from the results
© Prof. Dr. Michael Stal, 2011
Operations on Collections: filter
With filter you can filter elements from a list Useful to create views on lists
Page 47
let l = ["Martin"; "Erich"; "Kent"; "Gregor"; "Kevlin"]let view = l |> List.filter(fun elem -> elem.StartsWith("K"))
printfn "%A" view // => [“Kent”; “Kevlin”]
Put all those elements that fulfil the condition into the result list
© Prof. Dr. Michael Stal, 2011
Operations on Collections: fold
With fold and foldback you may iterate through a collection (from left to right respecitely from right to left) and apply a function
Let me give you an example
fold takes the current element in the collection it has iterated to, applies the specified function on the accumulator and this element, and passes the result to the next iteration as new accumulator
This can be used , for instance, to add all numbers in the collection as depicted in the example
Page 48
let l = [1 ; 2; 3; 4; 5 ]let sum a i = a + ilet result = List.fold sum 0 l printfn "result is %i" result // => 15
function Intitial value for accumulator
collection
© Prof. Dr. Michael Stal, 2011
Using Pipelining with Collections = Power!
Here the power of the pipeline operator can be leveraged Pipelining also improves readability
Page 49
let l = [1; 2; 3; 4; 5]let l2 = l |> List.map (fun x -> x * x) |> List.rev
printfn "%A" l2 // => [25; 16; 9; 4; 1]
Take the list, apply the operation to all ofIts elements, and revert the list
© Prof. Dr. Michael Stal, 2011
List Comprehensions
In functional programming recursion and comprehensions compensate for imperative loops
Lists can be easily generated using comprehensions
Sequences in F# are collections of type IEnumerable They are subject to lazy evaluation! let s = seq { for i in 1 .. 10 do yield i + 1 }
Page 50
// all values from 1 to 10let l1 = [ 1 .. 10 ]// all values from 1 to 9 in steps of 2let l2 = [ 1 .. 2 .. 9 ]// all squares for n from 1 upto 10 let l3 = [for n in 1 .. 10 do yield n * n]
© Prof. Dr. Michael Stal, 2011
Unfold on Sequences
Unfold generates a sequence using a function (opposite of fold) (´State -> ´T * ´State option) -> ´State -> seq<´T> Take current state and return an option tuple with
next element of sequence and next state The initial state value Generated sequence
Page 51
let fibI = Seq.unfold( fun state -> Some(fst state + snd state, (snd state, fst state + snd state)) ) (1I,1I)
let tmp = fibI |> Seq.take 100
for x in tmp do System.Console.WriteLine x
© Prof. Dr. Michael Stal, 2011
Records
Records are similar to tuples In records, however, fields are named Field names become accessors of the record type
Page 52
type usergroup = { topic: string; members: string list }
let fs_fans = { topic = "F#"; members = [ "Don"; "Michael"; "Ted"] }
printfn "topic is %s " fs_fans.topicprintfn "members: %A " fs_fans.members
// => topic is F#// members: ["Don"; "Michael"; "Ted"]
© Prof. Dr. Michael Stal, 2011
Cloning Records
You can clone records and overwrite their fields partially using with
Page 53
type person = { name : string; prefnum : int }let douglas = { name = "douglas";prefnum = 42 }let michael = { douglas with name = "michael"}printfn "%s %d" michael.name michael.preferred_num
© Prof. Dr. Michael Stal, 2011
Records and Pattern Matching
Alternatively you may use pattern matching for accessing and checking fields
Page 54
type usergroup = { topic: string; members: string list }let cs_DE = {topic = "C#"; members = ["Tim"; "Tom; Pit" ]}let fs_FR = {topic = "F#"; members = [ "Henry"; "Marc"; "Bert" ]}let rec findFSharpUGs (groups: usergroup list) = match groups with | { topic = "F#"; members = m } :: rest -> printfn "%A" m findFSharpUGs rest | _ :: rest -> findFSharpUGs rest | [] -> printfn "end of list"findFSharpUGs [cs_DE; fs_FR]
© Prof. Dr. Michael Stal, 2011
Discriminated Unions
One of the core type constructs in F# Aggregates different structures The name after | is called a constructor or discriminator
Page 55
type Content = stringtype BinTree = | Node of BinTree * BinTree | Leaf of Content// example usage:let bLeft = Node(Leaf("1.1"), Leaf("1.2"))let bRight = Leaf("2.1")let b = Node(bLeft, bRight)
© Prof. Dr. Michael Stal, 2011
Discriminated Unions and Pattern Matching
... Best served with Pattern Matching
Page 56
let rec treePrint b = match b with | Node(bl,br) -> printf "(" treePrint bl printf "|" treePrint br printf ")" | Leaf(c) -> printf "[%s]" ctreePrint b //=>(([1.1]|[1.2])|[2.1])
© Prof. Dr. Michael Stal, 2011
Example: Functions as Types
Functions are also types. Let‘s implement the Command pattern in F#
Page 57
type Command = Command of (int -> int)let command1 = Command(fun i -> i + 1)let command2 = Command(fun i -> i * i)let command3 = Command(fun i -> i / 3)
let rec exec commands = match commands with | [] -> printf "end" | Command(f) :: r -> let res = f 6 printfn "%i" res exec r // recursion on rest let cmdseq = [command1; command2; command3]exec cmdseq // => 7 <cr> 36 <cr> 2
© Prof. Dr. Michael Stal, 2011
Detour: Acquiring and Disposing Resources with use
The use operator in F# behaves similar to using in C# When acquiring a resource, use will make sure that the
Dispose method is called (object type must implement IDisposable)
When the scope of the object is left, no matter how, the resource will get deleted
Page 58
let writeAText () =use otf =
File.CreateText(@“QCON2011.txt")otf.WriteLine(“F# is fun!")
© Prof. Dr. Michael Stal, 2011
Enums
Enums in F# are expressed similar to discriminated unions
Page 59
type Ratings = | Excellent = 10 | Good = 7 | Average = 5 | Fair = 3 | Bad = 1
© Prof. Dr. Michael Stal, 2011
Mutual Recursive Types
Types in F# can not refer to types defined in a later part
You need to have a mutual recursive definition using and
Page 60
type Element = | Content of string | Ref of Tree // Error: Tree not definedtype Tree = | Node of Tree * Element * Tree | Leaf of Element
type Element = | Content of string | Ref of Treeand Tree = | Node of Tree * Element * Tree | Leaf of Element
© Prof. Dr. Michael Stal, 2011
Extend Pattern Matching with Active Patterns
For extending pattern matching you may define your own patterns This is done using active patterns as shown in the example:
Page 61
type Coordinate(x : float, y : float) = member c.x = x member c.y = y member c.r = Math.Sqrt(c.x**2.0+c.y**2.0) member c.a = Math.Atan(c.y / c.x)
let (|Polar|) (c : Coordinate) = (c.a, c.r)let printPolar c = match c with | Polar(a, r) -> printfn "a=%f r=%f" a rprintPolar(new Coordinate(1.0,1.0))
© Prof. Dr. Michael Stal, 2011
Another Example for Active Patterns
We can even provide patterns for existing (.NET) types
Page 62
let (|Int|Float|String|) (o : Object) = match o with | :? string -> String("42") | :? float -> Float(42.0) | :? int -> Int(42)
let rec print42 (o : Object) = match o with | String(s) -> Console.WriteLine("String : {0}",s) | Float(f) -> Console.WriteLine("Float : {0}",f) | Int(i) -> Console.WriteLine("Int : {0}",i) print42 "universe" // => String : 42
© Prof. Dr. Michael Stal, 2011
Partial Active Patterns
Partial patterns return Options
Page 63
let (|Even|_|) n = if (n % 2 = 0) // n mod 2 = 0 then Some(n) // yes => return Some(val) else None // no => return None
let checkEven n = match n with | Even(m) -> printfn "even" | _ -> printfn "odd"checkEven 12 // “even”checkEven 13 // “odd”
© Prof. Dr. Michael Stal, 2011
Keyword function
For pattern matching an interesting short exists using the keyword function
Page 64
// instead of:let rec combine2String sep s = match s with | [] -> "" | h :: t -> h.ToString() + sep + combine2String sep t
printfn "%s" (combine2String " " ["Hello ";"QCon"])
// you may also use:let rec combine2String’ sep = function | [] -> "" | h :: t -> h.ToString() + sep + combine2String’ sep t
printfn "%s" (combineToString’ " " ["Hello ";"QCon"])
© Prof. Dr. Michael Stal, 2011
On the Road to OOP
F# supports object-oriented programming The first step to OOP is assigning functionality to objects
Page 65
type Name = { first: string; middle : char; last: string } with override x.ToString() = x.first + " " + x.middle.ToString() + " " + x.last member x.printName = printfn "%s“ (x.ToString())let JFK : Name = { first = "John"; middle = 'F'; last = "Kennedy" }JFK.printName // => John F Kennedy
© Prof. Dr. Michael Stal, 2011
Object Expressions
We can also instantiate interfaces within a variable definition In the next slides we‘ll dive deeper into classes/interfaces in F#
Page 66
open Systemopen System.Collections.Genericlet comparer = { new IComparer <string> with // sort by length! member x.Compare(s1, s2) = let s1Len = s1.Length let s2Len = s2.Length s1Len.CompareTo(s2Len)}let a = [|"Peter"; "Mike"; "Tim"|] Array.Sort(a, comparer) // arrays are mutable!printfn "%A" a // => [| "Tim“; "Mike"; "Peter"|]
© Prof. Dr. Michael Stal, 2011
Defining Classes in F#
Classes in F# offer the same capabilities such as in C# For members we need to specify a instance name
Page 67
type Circle (radius : float, center: float * float) = static let UnitCircle = Circle(1.0, (float 0, float 0)) member v.scale(k) = Circle(k * radius, center) member v.radius = radius member v.center = center static member unitCircle = UnitCircle override v.ToString() = "r = " + v.radius.ToString() + " and c = " + v.center.ToString()let c = Circle(2.0, (3.0,4.0))System.Console.WriteLine c
© Prof. Dr. Michael Stal, 2011
Explicit Fields
let bindings always require initialization If you do not need an initialization,use explicit values instead! The attribute [<DefaultValue>] is required for values that should
will be initialized to zero. For types without zero initialization we must set fields in the constructor
Page 68
type Book (author : string, title : string) = [<DefaultValue>] val mutable rating : float [<DefaultValue>] val mutable readers : int member b.rate(current : float) = b.readers <- b.readers + 1
b.rating <- (b.rating + current) / b.readerslet fSharpBook = new Book (“Don Syme”, “Expert F#”)fSharpBook.readers <- 0fSharpBook.rating <- 0.0
© Prof. Dr. Michael Stal, 2011
Abstract Classes
Abstract types resp.classes must have an attribute AbstractClass Deriving from a base class requires the inherit keyword
Page 69
[<AbstractClass>]type Shape() = abstract draw: unit -> unit
type Circle (radius : float, center: float * float) = inherit Shape() // all the other members default v.draw() = printfn "%s" (v.ToString())
Use override for overriding implementations anddefault for overriding an abstract method
© Prof. Dr. Michael Stal, 2011
Visibility Annotations
F# support private, public, internal visibility Also applicable to modules
Page 70
type SpaceShip(name : string) = new() = new SpaceShip("NCC-1701") member private s.name = name member internal s.speed = ref(0) member public s.call(msg : string) = printfn "Got message %s" msg member public s.accelerate() = if (!s.speed < 8) then s.speed := !s.speed + 1 member public s.stopEngines() = s.speed := 0 member s.id with get() = s.name // and set(id) = ... if it were mutable
This is how you can add moreconstructors
© Prof. Dr. Michael Stal, 2011
Default and Optional Parameters
In F# 2.0 types, functions can have default and optional parameters In functions optional parameters have Option type!
Page 71
open Systemtype CoolProgrammingLanguage(?name : string, ?compile : bool) = let name = defaultArg name "F#" // default value let compile = true // optional parameter member x.Name = name member x.Compile = compile
let fsharp = new CoolProgrammingLanguage()// returns F# and true:Console.WriteLine(fsharp.Name + " " + fsharp.Compile.ToString())
© Prof. Dr. Michael Stal, 2011
Defining and Using Interfaces
Interfaces are defined as abstract types with only abstract members Using them in a class requires the interface keyword
Page 72
type IDraw = abstract draw: unit -> unit type Line(p1 : float * float, p2: float * float) = member l.p1 = p1 member l.p2 = p2 interface IDraw with member l.draw() = let lineWeight = 2 // ........... printfn "done"
© Prof. Dr. Michael Stal, 2011
Object Expressions and Interfaces
You may also instantiate an interface directly in a function
Page 73
type IDraw = abstract draw: unit -> unit
let point(p : float * float) = { new IDraw with member x.draw() = printfn "drawing the line" } point(2.0, 3.0).draw()// => drawing the line
© Prof. Dr. Michael Stal, 2011
Page 74
Advanced F#
© Prof. Dr. Michael Stal, 2011
Continuations
Continuations basically is „a function that receives the result of an expression after it’s been computed“
Page 75
// instead of writinglet x = 3let y = 4let e1 = x * y let e2 = e1 + 1
// we pass the continuation as an argument to // a function that takes the result and continues the // evaluation. This is an inside-out approach:let cont_e cont = cont (x * y) let e3 = cont_e (fun i -> i + 1)
© Prof. Dr. Michael Stal, 2011
Continuation Passing Style (CPS)
But why should we care about CPS? Let us use the following example
Problem: this can‘t be subject to TCO (Tail Call Optimization) Works well for balanced trees but not for unbalanced ones Solution: add an accumulator as extra argument
Page 76
type Tree =| Node of string * Tree * Tree| Tip of string
let rec size tree =match tree with
| Tip _ -> 1| Node(_,treeLeft,treeRight) ->
size treeLeft + size treeRight
© Prof. Dr. Michael Stal, 2011
CPS Case Study: Using an extra accumulator
We just add an extra parameter and we assume (!) the tree is skewed to the right (1 of 2 options)
The call recursing over the right branch is a tail call, the left one isn‘t Thus, we still risk a stack overflow for trees that are more skewed to the
left
Page 77
let rec sizeAcc acc tree =match tree with
| Tip _ -> 1 + acc| Node(_,treeLeft,treeRight) ->
let acc = sizeAcc acc treeLeftsizeAcc acc treeRight
let size tree = sizeAcc 0 tree
© Prof. Dr. Michael Stal, 2011
CPS Case Study: Using Continuations
By using continuations all branches will be tail-calls
The stack overflow problem has been eliminated
Page 78
let rec sizeCont tree cont =match tree with| Tip _ -> cont 1| Node(_,treeLeft,treeRight) ->
sizeCont treeLeft (fun leftSize ->sizeCont treeRight (fun rightSize ->
cont (leftSize + rightSize)))
let size tree = sizeCont tree (fun x -> x)
© Prof. Dr. Michael Stal, 2011
Reactive, Asynchronous and Parallel F#
Many things within an application happen asynchronously, such as Reading Web Pages Processing a GUI event
handler Waiting for I/O completion
In addition, we should leverage the power of Multicore CPUs
We need language support for reactive, asynchronous, and parallel processing
Page 79
Socket for Athlon 64 X2 CPUSource: Wikipedia
© Prof. Dr. Michael Stal, 2011
Using Mechanisms from the BCL
In the .NET BCL (Base Class Library) there are already some mechanisms available such as threads and background workers
We instantiate a BackgroundWorker from a pool of threads: let worker = new BackgroundWorker()
We then pass a function with code to the worker it should execute: worker.DoWork.Add(fun args -> .....)
In the next step we tell the worker which code to execute after its completion. An event will automtaically raised by the runtime . worker.RunWorkerCompleted.Add(fun args -> ...)
Finally we start the worker‘s execution which raises an event to start DoWork: worker.RunWorkerAsync()
Page 80
© Prof. Dr. Michael Stal, 2011
Complete Example: Calculating the nth Fibonacci
Page 81
let worker = new BackgroundWorker()let numIterations = 1000worker.DoWork.Add(fun args -> let rec computeFibonacci resPrevPrev resPrev i = let res = resPrevPrev + resPrev
if i = numIterations then args.Result <- box res // mutable access else computeFibonacci resPrev res (i+1) computeFibonacci 1 1 2)
worker.RunWorkerCompleted.Add(fun args -> MessageBox.Show(sprintf "Result = %A" args.Result) |> ignore)worker.RunWorkerAsync()
© Prof. Dr. Michael Stal, 2011
Async Example
Microsoft.FSharp.Control.Async<'T> allows to define asynchronous workflows
An Async instance will provide a result in the future (calling Start) let!, do!, return!, yield! imply asynchronous processing
Page 82
let fetchAsync(url:string) = async { let req = WebRequest.Create(url) let! resp = req.AsyncGetResponse() let resp = req.GetResponse let stream = resp.GetResponseStream() let reader = new StreamReader(stream) let! html = reader.AsyncReadToEnd() printfn "Read %d characters for %s..." html.Length url } Async.Start (fetchAsync(“http://fsharp.net”))
© Prof. Dr. Michael Stal, 2011
Async - Under the Hood
Internally, F# uses continuations. For example:
will be implemented as
Page 83
async { let req = WebRequest.Create("http://fsharp.net/") let! resp = req.AsyncGetResponse() let stream = resp.GetResponseStream() let reader = new StreamReader(stream) let! html = reader.AsyncReadToEnd() html }
async.Delay(fun () -> let req = WebRequest.Create("http://fsharp.net/") async.Bind(req.AsyncGetResponse(), (fun resp -> let stream = resp.GetResponseStream() let reader = new StreamReader(stream) async.Bind(reader.AsyncReadToEnd(), (fun html -> async.Return html)))
© Prof. Dr. Michael Stal, 2011
An Example for Parallel Execution
Page 84
open System.Threadingopen Systemlet parallelArrayInit n f = let currentLine = ref -1 // reference let res = Array.zeroCreate n let rec loop () = let y = // locking with Interlocked Interlocked.Increment(¤tLine.contents) if y < n then res.[y] <- f y; loop() Async.Parallel [ for i in 1 .. Environment.ProcessorCount -> async {do loop()} ] |> Async.Ignore |> Async.RunSynchronously reslet rec fib x=if x < 2 then 1 else fib(x-1)+fib(x-2)let it = parallelArrayInit 25 (fun x -> fib x)printfn "%A" it // => [|1; 1; 2; 3; 5; 8; 13; 21; 34; 55; 89; ... |]
© Prof. Dr. Michael Stal, 2011
Agent-based Programming
The class MailboxProcessor allows to implement agents which retrieve messages through their inbox
Page 85
let counter = new MailboxProcessor<_>(fun inbox -> let rec loop n = async{ printfn "n = %d, waiting..." n let! msg = inbox.Receive() return! loop (n+msg) } loop 0)Counter.Start() // enter loop in asynchronous agentCounter.Post(42) // send message “42” to agent
© Prof. Dr. Michael Stal, 2011
Summary
F# pragmatically combines imperative (C# roots) with functional programming (OCaml roots)
It runs on the CLR and thus offers interoperability with other CLI languages
Excellent features for concurrency and asynchronous operation
F# programs are compact and succinct causing less noise-to-signal ratio
Support for Windows, Mac OS, Linux Availability on Visual Studio 2010 implies
Microsoft is serious about functional languages
Start Coding with F#!
Page 86
© Prof. Dr. Michael Stal, 2011
Books: My Recommendations
D. Syme, A. Granicz, A. Cisternino: Expert F# 2.0 (Expert's Voice in F#), Apress; edition (June 7, 2010)
C. Smith: Programming F#: A comprehensive guide for writing simple code to solve complex problems (Animal Guide), O'Reilly Media; edition (October 13, 2009)
T. Petrícek, J. Skeet: Real World Functional Programming: With Examples in F# and C#, Manning Publications; edition (December 30, 2009)
A lot of more books available
Page 87
© Prof. Dr. Michael Stal, 2011
F# Tools
Lot of more available F# PowerPack: tools such as FsLex, FsYacc, (P)LINQ support,
additional classes, SI Units for Measure, ... Amazing examples on http://
code.msdn.microsoft.com/fsharpsamples xUnit.net for Unit Testing: http://xunit.codeplex.com/ or Nunit F# Web Tools: http://fswebtools.codeplex.com/
Page 88
© Prof. Dr. Michael Stal, 2011
F# Links
Interesting Links to F# information/sources Microsoft Research:
http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/ Microsoft MSDN: http://msdn.microsoft.com/en-us/fsharp/default Don Symes Web Log: http://blogs.msdn.com/b/dsyme/ F# Community Samples: http://fsharpsamples.codeplex.com/ hubFS – The Place for F#: http://cs.hubfs.net/ Thomas Petricek: http://tomasp.net/ F# Blog by Jon Harrop: http://fsharpnews.blogspot.com/ TechED präsentation by Don Syme: http://
blogs.msdn.com/b/dsyme/archive/2010/11/29/my-talk-at-teched-europe-2010-a-taste-of-f-today-and-future.aspx
YouTube: http://www.youtube.com/watch?v=uyW4WZgwxJE
Page 89
© Prof. Dr. Michael Stal, 2011
Summary
F# pragmatically combines imperative (C# roots) with functional programming (OCaml roots)
It runs on the CLR and thus offers interoperability with other CLI languages
Excellent features for concurrency and asynchronous operation
F# programs are compact and succinct causing less noise-to-signal ratio
Support for Windows, Mac OS, Linux Availability on Visual Studio 2010 implies
Microsoft is serious about functional languages
Start Coding with F#!
Page 90
© Prof. Dr. Michael Stal, 2011
Final Conclusions
Functional Programming is not restricted to academic research anymore
Big players already use the paradigm such as Facebook, Twitter, Ericsson
FP languages like Clojure, Erlang, Scala, F# are now ready for the mainstream
In addition, functional features have been integrated into Java, C++, C#, Ruby, Smalltalk, ..
CLR/JVM offer several benefits: Interoperability Availability of rich framework libraries Availability of powerful tools Availability of large communities
No Big Bang approach recommended. Start small, grow big
Distribute the word and let the force be with you
Page 91