Qcon2011 functions rockpresentation_f_sharp

91
© 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 [email protected]

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 of Qcon2011 functions rockpresentation_f_sharp

Page 1: Qcon2011 functions rockpresentation_f_sharp

© 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

[email protected]

Page 2: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 3: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 4: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 5: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 6: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 7: Qcon2011 functions rockpresentation_f_sharp

© 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)

Page 8: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 9: Qcon2011 functions rockpresentation_f_sharp

© 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/

Page 10: Qcon2011 functions rockpresentation_f_sharp

© Prof. Dr. Michael Stal, 2011

Example: Using Visual Studio 2010

Page 10

Editor Window

F# Interactive

SolutionExplorer

Page 11: Qcon2011 functions rockpresentation_f_sharp

© Prof. Dr. Michael Stal, 2011

F# in a Sandbox

URL: http://tryfs.net/

Page 11

Page 12: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 13: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 14: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 15: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 16: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 17: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 18: Qcon2011 functions rockpresentation_f_sharp

© 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 = ()

Page 19: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 20: Qcon2011 functions rockpresentation_f_sharp

© 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*)

Page 21: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 22: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 23: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 24: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 25: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 26: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 27: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 28: Qcon2011 functions rockpresentation_f_sharp

© 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>

Page 29: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 30: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 31: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 32: Qcon2011 functions rockpresentation_f_sharp

© 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|]

Page 33: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 34: Qcon2011 functions rockpresentation_f_sharp

© 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 = …

Page 35: Qcon2011 functions rockpresentation_f_sharp

© 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]

Page 36: Qcon2011 functions rockpresentation_f_sharp

© 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]

Page 37: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 38: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 39: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 40: Qcon2011 functions rockpresentation_f_sharp

© 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”;”!”;”!”]

Page 41: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 42: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 43: Qcon2011 functions rockpresentation_f_sharp

© 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"

Page 44: Qcon2011 functions rockpresentation_f_sharp

© 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“

Page 45: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 46: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 47: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 48: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 49: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 50: Qcon2011 functions rockpresentation_f_sharp

© 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]

Page 51: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 52: Qcon2011 functions rockpresentation_f_sharp

© 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"]

Page 53: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 54: Qcon2011 functions rockpresentation_f_sharp

© 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]

Page 55: Qcon2011 functions rockpresentation_f_sharp

© 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)

Page 56: Qcon2011 functions rockpresentation_f_sharp

© 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])

Page 57: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 58: Qcon2011 functions rockpresentation_f_sharp

© 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!")

Page 59: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 60: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 61: Qcon2011 functions rockpresentation_f_sharp

© 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))

Page 62: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 63: Qcon2011 functions rockpresentation_f_sharp

© 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”

Page 64: Qcon2011 functions rockpresentation_f_sharp

© 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"])

Page 65: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 66: Qcon2011 functions rockpresentation_f_sharp

© 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"|]

Page 67: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 68: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 69: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 70: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 71: Qcon2011 functions rockpresentation_f_sharp

© 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())

Page 72: Qcon2011 functions rockpresentation_f_sharp

© 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"

Page 73: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 74: Qcon2011 functions rockpresentation_f_sharp

© Prof. Dr. Michael Stal, 2011

Page 74

Advanced F#

Page 75: Qcon2011 functions rockpresentation_f_sharp

© 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)

Page 76: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 77: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 78: Qcon2011 functions rockpresentation_f_sharp

© 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)

Page 79: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 80: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 81: Qcon2011 functions rockpresentation_f_sharp

© 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()

Page 82: Qcon2011 functions rockpresentation_f_sharp

© 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”))

Page 83: Qcon2011 functions rockpresentation_f_sharp

© 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)))

Page 84: Qcon2011 functions rockpresentation_f_sharp

© 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(&currentLine.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; ... |]

Page 85: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 86: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 87: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 88: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 89: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 90: Qcon2011 functions rockpresentation_f_sharp

© 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

Page 91: Qcon2011 functions rockpresentation_f_sharp

© 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