qcon2011 functions rockpresentation_f_sharp

Post on 10-May-2015

1.748 Views

Category:

Education

0 Downloads

Preview:

Click to see full reader

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

Michael.Stal@siemens.com

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

© 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

top related