440 likes | 679 Views
Introduction to F#. Adam Granicz granicz.adam@intellifactory.com IntelliFactory , EPAM Systems. Making Programming Functional. F#. Agenda. Motivation for functional programming (FP) Functional programming concepts F# - constructs Functional, Language-oriented F# Interactive.
E N D
Introduction to F# Adam Graniczgranicz.adam@intellifactory.comIntelliFactory, EPAM Systems Making Programming Functional F#
Agenda • Motivation for functional programming (FP) • Functional programming concepts • F# - constructs • Functional, Language-oriented • F# Interactive
Motivation - What we would like • Programmers make mistakes so we need • More effective abstractions to express what we need in fewer lines of code • Better type systemto guard from misuse • These can give us • Abstractions/Type System Few or no conceptual errors • Fewer LoCFewer bugs, better maintainability
Motivation - and we really wish for… • Program Synthesis • Generate programs based on a specification • A shift towards declarative programming • Eliminate programming errors for good • Program Correctness • Verify that a program fulfills its specification • Theorem provers, model checkers, etc.
Functional concepts • Higher-order functions • Functions that take function parameters and/or return functions as result • Functions are first-class values • Anonymous functions • Immutability • Values are NOT mutable • Currying • Partial function application yields a function
Functional concepts • (Parametric) Polymorphism • ADTs are truly polymorphic: Map<‘t1, ‘t2> • Type inference • No need to type annotate programs, types are automatically inferred from use
Functional concepts • Lazy vs. eager evaluation • Values are evaluated when needed versus when they are encountered • Recursion • Problem solving is done by recursively breaking down a larger problem into small ones • Mutually Recursive and Recursive types • Recursive values Delayed evaluation
F# • Functional, object-oriented • Strongly-typed (type-safe), type inferred, garbage collected • Succint, expressive, composable • Interoperable with any .NET language • .NET runtime support, tools, libraries • http://research.microsoft.com/fsharp/fsharp.aspx
F# code sample • … Edit text and revise your documents
F# constructs • 1 Functional • 1.1 Concise syntax • 1.2 Data abstractions • discriminated unions, pattern matching polymorphic abstract data structures • type augmentation • 1.3 Control abstractions • Computation expressions (sequences, workflows) • 2 Imperative (loops, mutable cells, exceptions, IO) • 3 Object-oriented (classes, interfaces) • 4 Language-oriented • Active patterns, reflection, quotations, AST representations
1.1 F# syntax • Traditionalvs. #light syntax • Indentation matters, fewer keywords, more readable code • let f a b = let f a b = • let c,d = a+b, a–b inlet c,d = a+b, a-b • c*d c*d • Piping functions • Encourages a more functional style, helps in type inference • let (|>) x f = f x • let (>>) f g x = g (f x)
1.2 Abstractions – Data types • Discriminated unions • type exp = • | Number of int • | Add of exp * exp • | Subtract of exp * exp • | Multiply of exp * exp • | Divide of exp * exp
1.2 Abstractions – Data types • Pattern matching • letreceval = function • | Number i -> i • | Add (e1, e2) -> eval e1 + eval e2 • | Subtract (e1, e2) -> eval e1 - eval e2 • | Multiply (e1, e2) -> eval e1 * eval e2 • | Divide (e1, e2) -> eval e1 / eval e2
1.2 Abstractions – Data types • Polymorphic abstract data structures • List<‘a>, Array<‘a>, Seq<‘a> • Map<‘a, ‘b>, Set<‘a>, etc… • type ‘a tree = • | Node of ‘a * ‘a tree * ‘a tree • | Leaf
1.2 Abstractions – Data types • Tuples • Pairs of values • (1, 2) • ((1, 2), (1, 2)) • ([1; 2; 3], 4) • Also, n-tuples • (1, 2.0, “3”, 4I, ..) • Also, options, records, lists, arrays, sequences, etc.
1.2 Abstractions – Type augmentation • Enriching a complex type • typetrig = • | Number of double • | Sin of trig • | Cos of trig • | Add of trig * trig • | Mulof trig * trig • | Inv of trig • with • static member Tan t = Mul (Sin t, Inv (Cos t)) • static member Cot t = Mul (Cos t, Inv (Sin t)) • static member (/) (t1, t2) = Mul (t1, Inv t2) • end
1.2 Abstractions – Type augmentation • Augmenting existing types • module NumberTheoryExtensions = • let isPrime(i) = • let lim = int(sqrt(float(i))) • let rec check j = • j > lim or (i % j <> 0 && check (j+1)) • check 2 • typeSystem.Int32 with • member i.IsPrime = isPrime(i) Edit text and revise your documents
1.2 Abstractions – Type augmentation • Augmenting existing types • > open NumberTheoryExtensions;; • > (3).IsPrime;; • val it : bool = true • > (6093711).IsPrime;; • val it : bool = false Edit text and revise your documents
1.3 Computation expressions / Workflows • Sequence expressions • building, generating, and operating on sequences, lists, and arrays • Asynchronous workflows • Probabilistic workflows • Other workflows • workflow builders + syntax desugaring • Quoted workflows quotations (language-oriented)
1.3.1 Sequence expressions - building • Building sequences using range expressions • > seq {0 .. 2};; • val it : seq<int> = seq [ 0; 1; 2; ] • > seq {-100.0 .. 100.0};; • val it : seq<double> = seq [ -100.0; -99.0; -98.0; ... ] • > seq {1I .. 1000000000000I};; • val it : seq<bigint> = seq [ 0I; 1I; 2I; 3I; ... ] • Using a skip value • > seq { 0 .. 2 .. 5 };; • val it : seq<int> = seq [ 0; 2; 4 ]
1.3.1 Sequence expressions - iterating • > let range = seq {0 .. 2 .. 6};; • val range : seq<int> • > foriin range do • printfn"i = %d" i;; • i = 0 • i = 2 • i = 4 • i = 6
1.3.1 Sequence expressions – aggregation • open System.IO • letrecallFiles dir = • Seq.append • (dir |> Directory.GetFiles) • (dir |> Directory.GetDirectories • |> Seq.map allFiles |> Seq.concat) • > let files = allFiles @"c:\projects";; • valfiles : seq<string> • > files;; • val it : seq<string> • = seq["c:\\projects\\AmazonSalesRank\\AmazonSalesRank.sln"; ...
1.3.1 Sequence comprehensions • let squares = seq { foriin 1 .. 100 -> (i, i*i) } • let recallFiles2 dir = • seq { for file inDirectory.GetFiles dir • -> file • forsubdirin Directory.GetDirectories dir • ->> allFiles2 subdir} Comprehensions can also be used to construct lists and arrays: letlst = [ for i in 1 .. 100 -> (i, i*i) ] let arr = [| for i in 1 .. 100 -> (i, i*i) |]
1.3.1 Turning files into on-demand sequences • let reader = • seq{ use reader = • new StreamReader(File.OpenRead("t.txt")) • while not reader.EndOfStreamdo • -> reader.ReadLine() } • > reader |> Seq.take 3;; • First line... • Second line... • Third line...
1.3.1 Recursive sequences • Random walk: • let recrandomWalk k = • seq{ yield k • yield!randomWalk (k+rnd.NextDouble()-0.5) } • > randomWalk 10.0;; • val it: seq<float> = seq [10.0; 10.23817784; 9.956430122; 10.18110362; ...] Edit text and revise your documents
1.3.2 Asynchronous workflows – fetching pages • let museums = [ "MOMA", "http://moma.org/"; • "British Museum“, "http://www..../"; • "Prado", "http://museoprado.mcu.es" ] • let fetchAsync (nm, url: string) = • async { do printfn "Creating request for %s..." nm • letreq = WebRequest.Create(url) • let!resp = req.GetResponseAsync() • doprintfn "Getting response for %s..." nm • let stream = resp.GetResponseStream() • doprintfn "Reading response for %s..." nm • let reader = new StreamReader(stream) • let! html = reader.ReadToEndAsync() • doprintfn "Read %d for %s..." html.Length nm }
1.3.2 Asynchronous workflows – fetching pages • for nm,url in museums do • Async.Spawn (fetchAsync(nm, url));; • > Creating request for British Museum... • Creating request for MOMA... • val it : unit = () • > Creating request for Prado... • Getting response for Prado... • Reading response for Prado... • Read 1456 for Prado... • Getting response for MOMA... • Reading response for MOMA... • Read 42918 for MOMA... • Getting response for British Museum... • Reading response for British Museum... • Read 22131 for British Museum...
1.3.2 Asynchronous workflows – file processing • open Microsoft.FSharp.Control • open Microsoft.FSharp.Control.CommonExtensions • let numImages = 200 • let size = 512 • let numPixels = size*size • let ProcessImageAsync(i) = • async{ use inStream = File.OpenRead( • sprintf"Image%d.tmp" i) • let! pixels = inStream.ReadAsync(numPixels) • let pixels' = TransformImage(pixels,i) • use outStream = File.OpenWrite( • sprintf "Image%d.done" i) • do!outStream.WriteAsync(pixels')}
1.3.2 Asynchronous workflows – file processing • letProcessImagesAsync() = • let tasks = [ for i in 1 .. numImages • -> ProcessImageAsync(i) ] • Async.Run(Async.Parallel tasks) |> ignore
1.3.4 Other workflows - How do they work? Computation Builders + syntax desugaring
2/3 Imperative and object-oriented programming • 2 Imperative (loops, mutable cells, exceptions, IO) • 3 Object-oriented (classes, interfaces)
4 Language-oriented programming • Active patterns • Provide a way to hide/abstract away internalrepresentations • Reflection • Quotations • A mechanism to access the underlying syntaxrepresentation of F# code. • LINQ
4.1 Active patterns • Extensible pattern matching • Provide a way to hide/abstract away internal representations • open Microsoft.FSharp.Math • let (|Rect|) (x:complex) = (x.RealPart, x.ImaginaryPart) • let (|Polar|) (x:complex) = (x.Magnitude, x.Phase)
4.1 Active patterns • > let c = Complex.mkRect(3.0, 4.0);; • val c : complex • > c;; • val it : complex = 3.0r+4.0i • > match c with • | Rect(x,y) -> printfn "x = %g, y = %g" x y;; • x = 3, y = 4 • val it : unit = () • > match c with • | Polar(x,y) -> printfn "x = %g, y = %g" x y;; • x = 5.0, y = 0.927295 • val it : unit = ()
4.2 Reflection • Obtaining representationsof assemblies, type definitions, and member signatures • Via .NET reflection API • > let intListType = typeof<int list>;; • valintListType : System.Type • > intListType.FullName;; • val it : string = "Microsoft.FSharp.Collections.List`1[[System.Int32, mscorlib,Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" Edit text and revise your documents
4.3 Quotations • A mechanism to access the underlying syntax representation of F# code. • let plusExpr = <@ 1 + 1 @>;; • valplusExpr : Expr<int> • > plusExpr;; • val it : Expr<int> • = <@ Microsoft.FSharp.Core.Operators.op_Addition (Int32 1) (Int32 1) @> Edit text and revise your documents
4.4 Quotations and LINQ – In-memory objects • In-memory objects / collections • Native support via aggregate functions • let select = Seq.map • let where = Seq.filter • let people = [| ("Joe", 27, "Sales"); • ("Rick", 35, "Marketing"); • ("Mark", 40, "Sales"); • ("Rob", 31, "Administration"); • ("Bob", 34, "Marketing") |] • let namesR = • people |> select (fun (name, age, dept) -> name) • |> where (fun name -> name.StartsWith "R") Edit text and revise your documents
4.4 Quotations and LINQ – XML • XML • Functional construction of XML documents • mutation Edit text and revise your documents
4.4 Quotations and LINQ – Linq2Sql • Access to query syntax via F# quotations • Transform F# quotations to LINQ expressions • val SQL : Expr<'a> -> 'a • let res = • SQL <@ { for emp in (#db.Employees) • when emp.BirthDate.Value.Year > 1960 • && emp.LastName.StartsWith "S" • -> (emp.FirstName, emp.LastName) } @> • |> take 5 • for (first, last) in res do • printfn "%s %s" first last Edit text and revise your documents
F# Interactive (fsi.exe) • Command-line
F# Interactive (fsi.exe) • Visual Studio plug-in
Reading more about F# Expert F#Apress – 2007 Dec 7 Don Syme, Adam Granicz, Antonio Cisternino