Upcoming SlideShare
×

# Qcon2011 functions rockpresentation_f_sharp

2,054 views

Published on

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

Published in: Education
2 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
Your message goes here
• Be the first to comment

Views
Total views
2,054
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
31
0
Likes
2
Embeds 0
No embeds

No notes for slide

### Qcon2011 functions rockpresentation_f_sharp

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