31 ĐỀ THI THỬ VÀO LỚP 10 - TIẾNG ANH - FORM MỚI 2025 - 40 CÂU HỎI - BÙI VĂN V...
Qcon2011 functions rockpresentation_f_sharp
1. Functions rock!Harnessing the Power of Functional Part II: Programming with F# TUTORIAL QCON 2011, London Prof. Dr. Michael Stal Michael.Stal@siemens.com
2. Objectives of Presentation Introducing core concepts of Functional Programming Introducing F# as example Presentingthe 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
3. Whatis 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
4. Functional ProgrammingLanguages … Are oftenhybrid 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
5. Preconception: Functional LanguagesareSlow Isnottrueanymoredue to: HighlyefficientVMslikethe CLR, JVM StructuralSharing, no naive copying TailCallOptimization: at least someVMs Veryefficient and powerfulLibraries Easy leveraging of Concurrency (e.g., because of immutablity) Page 5
6. „Nowforsomethingcompletely 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
10. 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/
11. Example: Using Visual Studio 2010 Page 10 Solution Explorer Editor Window F# Interactive
12. F# in a Sandbox URL: http://tryfs.net/ Page 11
13. 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
14. 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
15. 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 = 5 let x = x + 5 // val x : int = 10 let x = x - 9 // val x : int = 1
16. 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 // => valpoly1 float -> float poly1 1.5 // => val it : float = 4 A closure let poly1 x = 2.0 * x *x - x + 1.0 // => valpoly1 float -> float
17. UsingClosures in F# Closuresrepresentfirst-classfunctionsthatcontainfree variables They bind free variables to theirdefinitioncontext Page 16 let a = 42 let 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 binding Closure
18. 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 = 12 let l : int List = [1; 2; 3] let twice (x: float) = 2.0 * x
19. Special Types: unit unit represents an expression or function with no value Page 18 printfn"QCon 2011 rocks!";; QCon2011 rocks! type is : valit : unit = () let printHello = printfn“Hello” type is : valprintHello: unit = ()
20. 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
21. 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 *)
22. 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
23. Currying and Partial Function Application F# supports partial function application: Page 22 > let mult x y = x * y;; valmult : 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 of mult with first param 2
24. 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
25. 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: #light let avg (a,b,c) = let sum(a,b,c) = a + b + c sum(a,b,c) / 3 let d = avg(1,2,3) printfn “and the average is %i” d // => 2
26. Operator Overloading in F# It is possible to define/overload operators Code Example: Page 25 let (*) a b = a + b let a = 2 * 7 // => a = 9 // may also be used in prefix notation: (*) 2 6 // => 8 // for unary operators: let (~-) n = 1 – n - 88 // => -87
27. 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 exceptionEvenArgument of int let printNumber n = if (n % 2 = 0) then raise (EvenArgument n) else printfn "%i" n try printNumber5 // ok printNumber4 // => exception EvenArgument 4 with EvenArgument x -> printfn "Number %i is even!" x
28. The Pipeline Operator |> The pipeline |> operator is very powerful let (|>) x f = f x // applyfunction 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
29. 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 error let distance = 100.0<m> let time = 5.0<s> let speed = (distance/time) let distanceInAnHour = speed * 3600.0<s>
30. 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
31. 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 elements let names = [| "Mick"; "Keith"; "Mark" |] // sequence expressions let squares = [| for i in 1..10 -> i * i |] // initialized array: 10 elems with 0 let ai : int array = Array.zeroCreate 10 // multidimensional 3 x 3 array let matrix : int array[,] = Array2D.zeroCreate 3 3
32. 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 slice let subarr = squares.[3..5] // get element printfn "%d" ai.[2] // modify element ai.[2] <- 6
33. 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|]
34. 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.Azure Application.Run form
35. Modules F# Modulescancontainvalues, typedefinitions, submodules Modulesarecompiled as classeswithstaticmembers Page 34 moduleMathModule letrechcf (a:bigint) (b:bigint) = if a = 0I then b elif (a < b) thenhcf a (b-a) elsehcf (a-b) b type Rational(a: bigint, b: bigint) = let n = hcf a b memberr.a = a / n memberr.b = b / n staticmember (+) r1 r2 = …
36. 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] => valmakeList : 'a -> 'a -> 'a list makeList 1 2 => valit : int list = [1; 2]
37.
38. 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 = 1 let ad = ("Adam", 7) // val ad : string * int = ("Adam", 7) let swap (a,b) = (b,a) // val swap : 'a * 'b -> 'b * 'a
39. 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
40. 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
41. Land of Lists Lists are the core datatype of all functional languages F# provides excellent support for lists Page 40 let l = [] // empty list let l2 = "Hello" :: ", " :: l // add elements at the head let l3 = ["London"] let l4 = l2 @ l3 // concatenate two lists let l5 = l4 @ ["!";"!"] let l6 = List.rev l5 // reverse order printfn "%A" l5 => [“Hello”;”, “;”London”;”!”;”!”]
42. And even more on Lists Several additional functions provided for lists In addition, List contains many static members Page 41 let l = [ 'a'; 'b'; 'c'; 'd' ] printfn "%c" l.Head // => a printfn "%A" l.Tail // => [‘b’;’c’;’d’] printfn "%d" l.Length // => 4 let lzip = List.zip [1; 2; 3] ['a';'b';'c'] printfn "%A" lzip // => [(1, 'a'); (2, 'b'); (3, 'c')] let arr = List.toArraylzip // make array
43. 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 l printfn "%i" sum => 15
44. 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"
45. 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“
46. 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 x printfn "%i" (apply (fun _ -> 42) 12) // => 42
47. 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
48. 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
49. Operations on Collections: fold With foldand foldbackyou 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 + i let result = List.foldsum 0 l printfn "result is %i" result // => 15 collection function Intitial value for accumulator
50. UsingPipeliningwithCollections = 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 of Its elements, and revert the list
51. 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 typeIEnumerable 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 10 let l1 = [ 1 .. 10 ] // all values from 1 to 9 in steps of 2 let l2 = [ 1 .. 2 .. 9 ] // all squares for n from 1 upto10 let l3 = [for n in 1 .. 10 do yield n * n]
52. 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.take100 for x in tmp do System.Console.WriteLine x
53. 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.topic printfn "members: %A " fs_fans.members // => topic is F# // members: ["Don"; "Michael"; "Ted"]
54. 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
55. 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]
56. 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 = string type 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)
57. Discriminated Unions and Pattern Matching ... Best served with Pattern Matching Page 56 let rec treePrint b = match b with | Node(bl,br) -> printf "(" treePrintbl printf "|" treePrintbr printf ")" | Leaf(c) -> printf "[%s]" c treePrint b //=>(([1.1]|[1.2])|[2.1])
58. 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
59. Detour: Acquiring and Disposing Resources withuse Theuseoperator in F# behavessimilar to using in C# Whenacquiring a resource, use will makesurethatthe Disposemethodiscalled (objecttypemustimplementIDisposable) Whenthescope of theobjectisleft, no matter how, theresource will getdeleted Page 58 let writeAText () = useotf = File.CreateText(@“QCON2011.txt") otf.WriteLine(“F# is fun!")
60. Enums Enums in F# areexpressedsimilar to discriminatedunions Page 59 type Ratings = | Excellent = 10 | Good = 7 | Average = 5 | Fair = 3 | Bad = 1
61. 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 defined type Tree = | Node of Tree * Element * Tree | Leaf of Element type Element = | Content of string | Ref of Tree and Tree = | Node of Tree * Element * Tree | Leaf of Element
62. Extend Pattern Matching with Active Patterns For extending pattern matching you may define yourown 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 r printPolar(new Coordinate(1.0,1.0))
63. 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
64. 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”
65. Keywordfunction For patternmatching an interestingshortexistsusingthekeywordfunction 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"])
66. 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
67. 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 System open System.Collections.Generic let 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"|]
68. DefiningClasses in F# Classes in F# offerthesamecapabilities such as in C# For membersweneed to specify a instancename 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
69. Explicit Fields letbindingsalwaysrequireinitialization Ifyou do notneed an initialization,useexplicitvaluesinstead! Theattribute[<DefaultValue>] isrequiredforvaluesthatshould will beinitialized to zero. For typeswithoutzeroinitializationwemustsetfields in theconstructor 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.readers let fSharpBook = new Book (“Don Syme”, “Expert F#”) fSharpBook.readers <- 0 fSharpBook.rating <- 0.0
70. Abstract Classes Abstract typesresp.classesmusthave an attributeAbstractClass Derivingfrom a baseclassrequirestheinheritkeyword 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()) Useoverrideforoverridingimplementations and defaultforoverriding an abstractmethod
71. VisibilityAnnotations F# support private, public, internalvisibility Also applicable to modules Page 70 Thisishowyou canaddmore constructors type SpaceShip(name : string) = new() = new SpaceShip("NCC-1701") member private s.name = name member internals.speed = ref(0) member publics.call(msg : string) = printfn "Got message %s" msg member publics.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
72. 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 System type 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())
73. Defining and Using Interfaces Interfaces aredefined as abstracttypeswithonlyabstractmembers Usingthem in a classrequirestheinterfacekeyword 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"
74. ObjectExpressions and Interfaces Youmay also instantiate an interfacedirectly in a function Page 73 typeIDraw = abstractdraw: unit -> unit let point(p : float * float) = { newIDrawwith member x.draw() = printfn "drawing the line" } point(2.0, 3.0).draw() // => drawingtheline
76. Continuations Continuationsbasicallyis „a function that receives the result of an expression after it’s been computed“ Page 75 // instead of writing let x = 3 let y = 4 let 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)
77. ContinuationPassing Style (CPS) Butwhyshouldwecareabout CPS? Letususethefollowingexample Problem: this can‘t be subject to TCO (Tail Call Optimization) Works well forbalancedtreesbutnotforunbalancedones 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
78. CPS CaseStudy: Using an extra accumulator We just add an extra parameter and weassume (!) thetreeisskewed 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 recsizeAcc acc tree = match tree with | Tip _ -> 1 + acc | Node(_,treeLeft,treeRight) -> let acc = sizeAcc acc treeLeft sizeAcc acc treeRight let size tree = sizeAcc 0 tree
79. CPS CaseStudy: UsingContinuations Byusingcontinuations all branches will betail-calls Thestackoverflowproblem has beeneliminated Page 78 let recsizeCont tree cont = match tree with | Tip _ -> cont 1 | Node(_,treeLeft,treeRight) -> sizeConttreeLeft (fun leftSize -> sizeConttreeRight (fun rightSize -> cont (leftSize + rightSize))) let size tree = sizeCont tree (fun x -> x)
80. Reactive, Asynchronous and Parallel F# Manythingswithin an applicationhappenasynchronously, such as Reading Web Pages Processing a GUI eventhandler Waitingfor I/O completion In addition, weshouldleveragethe power of Multicore CPUs Weneedlanguagesupportforreactive, asynchronous, and parallel processing Page 79 SocketforAthlon 64 X2 CPU Source: Wikipedia
81. 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
82. Complete Example: Calculating the nth Fibonacci Page 81 let worker = new BackgroundWorker() let numIterations = 1000 worker.DoWork.Add(fun args -> let rec computeFibonacciresPrevPrevresPrev i = let res = resPrevPrev + resPrev if i = numIterations then args.Result <- box res // mutable access else computeFibonacciresPrev res (i+1) computeFibonacci 1 1 2) worker.RunWorkerCompleted.Add(fun args -> MessageBox.Show(sprintf "Result = %A" args.Result) |> ignore) worker.RunWorkerAsync()
83. 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.Lengthurl} Async.Start (fetchAsync(“http://fsharp.net”))
84. 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.Returnhtml)))
85. An Example for Parallel Execution Page 84 open System.Threading open System let parallelArrayInit n f = let currentLine = ref -1 // reference let res = Array.zeroCreate n let rec loop () = let y = // locking with Interlocked Interlocked.Increment(¤tLine.contents) if y < n then res.[y] <- f y; loop() Async.Parallel[ for i in 1 .. Environment.ProcessorCount-> async{do loop()} ] |> Async.Ignore |> Async.RunSynchronously res let 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; ... |]
86. 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 agent Counter.Post(42) // send message “42” to agent
87. 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
88. 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
89. 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
90. 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
91. 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
92. Final Conclusions Functional Programmingisnotrestricted to academic researchanymore Big playersalreadyusetheparadigm such as Facebook, Twitter, Ericsson FP languageslikeClojure, Erlang, Scala, F# arenowreadyforthemainstream In addition, functionalfeatureshavebeenintegratedinto Java, C++, C#, Ruby, Smalltalk, .. CLR/JVM offerseveralbenefits: Interoperability Availability of richframeworklibraries Availability of powerfultools Availability of large communities No Big Bang approachrecommended. Start small, growbig Distributetheword and letthe force bewithyou Page 91