Date post: | 14-Dec-2015 |
Category: |
Documents |
Upload: | arely-denne |
View: | 232 times |
Download: | 0 times |
F#
Introduction to F#
Making Programming Functional
Adam [email protected]
IntelliFactory, EPAM Systems
Agenda
Motivation for functional programming (FP)
Functional programming concepts
F# - constructsFunctional, 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 system to guard from misuse
These can give us• Abstractions/Type System
Few or no conceptual errors• Fewer LoC
Fewer 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 resultFunctions are first-class valuesAnonymous 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# constructs1 Functional
1.1 Concise syntax
1.2 Data abstractions
discriminated unions, pattern matchingpolymorphic 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-orientedActive patterns, reflection, quotations, AST representations
1.1 F# syntax
Traditional vs. #light syntaxIndentation matters, fewer keywords, more readable code
let f a b = let f a b =let c,d = a+b, a–b in let c,d = a+b, a-bc*d c*d
Piping functionsEncourages a more functional style, helps in type inference
let (|>) x f = f xlet (>>) 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
let rec eval = 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
TuplesPairs 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
type trig = | Number of double | Sin of trig | Cos of trig | Add of trig * trig | Mul of 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
Edit text and revise your documents
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
type System.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
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>
> for i in range do printfn "i = %d" i;;i = 0i = 2i = 4i = 6
1.3.1 Sequence expressions – aggregation
open System.IOlet rec allFiles dir = Seq.append (dir |> Directory.GetFiles) (dir |> Directory.GetDirectories |> Seq.map allFiles |> Seq.concat)
> let files = allFiles @"c:\projects";;val files : seq<string>
> files;;val it : seq<string>= seq ["c:\\projects\\AmazonSalesRank\\
AmazonSalesRank.sln"; ...
1.3.1 Sequence comprehensions
let squares = seq { for i in 1 .. 100 -> (i, i*i) }
let rec allFiles2 dir = seq { for file in Directory.GetFiles dir -> file for subdir in Directory.GetDirectories dir ->> allFiles2 subdir }
Comprehensions can also be used to construct lists and arrays:
let lst = [ 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.EndOfStream do
-> reader.ReadLine() }
> reader |> Seq.take 3;;First line...Second line...Third line...
Edit text and revise your documents
1.3.1 Recursive sequences
Random walk:
let rec randomWalk 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; ...]
1.3.2 Asynchronous workflows – fetching pageslet 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 let req = WebRequest.Create(url) let! resp = req.GetResponseAsync() do printfn "Getting response for %s..." nm let stream = resp.GetResponseStream() do printfn "Reading response for %s..." nm let reader = new StreamReader(stream) let! html = reader.ReadToEndAsync() do printfn "Read %d for %s..." html.Length
nm }
1.3.2 Asynchronous workflows – fetching pagesfor 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 processingopen Microsoft.FSharp.Controlopen Microsoft.FSharp.Control.CommonExtensions
let numImages = 200let size = 512let 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
let ProcessImagesAsync() = let tasks = [ for i in 1 .. numImages -> ProcessImageAsync(i) ] Async.Run (Async.Parallel tasks) |> ignore
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 internal representations
Reflection
QuotationsA mechanism to access the underlying syntax
representation 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 = 4val it : unit = ()
> match c with| Polar(x,y) -> printfn "x = %g, y = %g" x y;;x = 5.0, y = 0.927295val it : unit = ()
Edit text and revise your documents
4.2 Reflection
Obtaining representations of assemblies, type definitions, and member signatures
Via .NET reflection API
> let intListType = typeof<int list>;;val intListType : 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 @>;;val plusExpr : 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.maplet where = Seq.filterlet 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
XMLFunctional 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 doprintfn "%s %s" first last