functional programming in f#
DESCRIPTION
TRANSCRIPT
Dmitri Nesteruk dmitrinesteruk @ gmail.com http://spbalt.net
“…a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data”
—Wikipedia
Higher-order functions i => j => f(j)
Pure functions Immutability No side effects
(Tail) recursion let f(x) = …; f(x-1);
Pattern matching
Math Probabilistic models
Symbolic processing (parsing/lexing) Symbolic differentiation Circuit verification
Multi-paradigm language in .NET stack Functional Imperative
Performance similar to C# Interactive console Support in Visual Studio
Debugger Editor
Mono support
#light printfn “Hello, F#!”
#light Light syntax – cuts down on ceremony when writing code Indentation instead of begin/end Use of in,done keywords not required No semicolons Currently mandatory – will be default in future
printfn “Hello, F#” Writes a line to the console A top-level binding (like a global function) Part of FSharp.Core
Referenced implicitly
Appears in a generated _main() Can “Go To Definition”
Can do it with a function
let sayHello = printfn “Hello, F#!” sayHello
Or pass a parameter
let sayHello s = printfn s sayHello "Hello, F#!"
Application operator |> (forward pipe)
let sayHello s = s |> printfn // same as printfn s
Explicit types
let length a = a.Length; // not ok let length (a:string) = a.Length // ok
Recursive definition
let rec factorial n = if n <= 1 then 1 else n * factorial(n‐1)
Mutual recursion
let rec funcA x = 1 + funcB(x) and funcB x = 1 – funcA(x)
One statement per line, use in for more let powerOf4 x =
let y = x * x in y * y
No implicit conversions let GetXName xname =
XName.op_Implicit(xname)
Aggressive strong typing let o:obj = “test”; // fails let o = box “test”; // ok
Mutability must be explicit mutable keyword variable <‐ value to assign
Clever switch statement Can match values of any type
let matchMe x = match x with | 1 ‐> printfn "one" | 2 ‐> printfn "two" | _ ‐> printfn "something else"
Cannot bind same pattern element twice Cannot match (x, x) Can match (x, y) when x = y
Tuple Option value Array Sequence List
Contains several values of any types No more Pair<T,U> etc. classes
let sumAndProduct a b = (a+b, a*b)
let (s, p) = sumAndProduct 2 3 printfn "%d %d" s p
Tuples use comma , Other structures use semicolon ;
null is typically not used with F# types Presence or absence can be discriminated with
an option value, which is None Some of 'a
Use pattern matching
match x with | Some(name) ‐> printfn name | None ‐> printfn “anonymous”
Your typical CLR array
let people = [| “john”; “jane”; “jack” |]
people.Length yields 3
Enumerable values let a = seq [1; 2; 3] let b = seq { for i in 1 .. 10 ‐> (i*i) }
Lazy-inited seq { 1 .. 10000000 }
Step seq { 1 .. 2 .. 10 } yields 1, 3, 5, 7, 9
Strings are char sequences printfn "%d" (Seq.length "Hello")
Iterated with for .. in .. do for i in mySeq do printfn “%d” i
Linked list of values
[1; 2; 3]
Has head and tail Head is the first element Tail is everything else [] is the empty list [1, 2, 3] has length of 1:)
let a = [1; 2; 3] Head = 1 Tail = [2; 3] let b = 0 :: a
[0; 1; 2; 3] let c = a @ b
[1; 2; 3; 0; 1; 2; 3]
let rec sumAll myList = match myList with | h :: t ‐> head + sumAll(t) | [] ‐> 0
let rec nonZero myList = match myList with | 0 :: t ‐> 1 :: nonZero t | h :: t ‐> h :: nonZero t | [] ‐> []
let rec htmlDecode text = match text with | ‘&’ :: ‘g’ :: ‘t’ :: ‘;’ :: tail ‐> ‘>’ :: htmlDecode tail // and so on
A non-exhaustive match will throw a MatchFailureException
Patterns can be grouped match person with
| a :: (b :: c as subGroup) ‐> match subGroup with
Anonymous functions Functional composition Partial application Memoization
A way of defining nameless functions fun x ‐> x * 2
Can be passed as parameter Can be bound, i.e.
let square = fun x ‐> x * x
Used to provide LINQ-like features to lists and sequences let myList = [1; 2; 3] List.iter (fun f ‐> printfn “%d” f) myList
Iterates through the collection
List.map (fun f ‐> f + 1) myList Returns a modified list [2; 3; 4] – LINQ Select()
List.filter (fun f ‐> f % 2 = 0) myList Returns only odd elements – LINQ Where()
Other useful functions (e.g., List.to_array) Similar features in seq
Operators can be piped values |> List.map (fun f ‐> f + 1)
|> List.filter(fun f ‐> f > 0)
And functionally composed let even = List.filter
(fun f ‐> f % 2 = 0) let positive = List.filter (fun f ‐> f > 0) let evenAndPos = even >> positive
evenAndPos [1; ‐2; 4] yields [4]
let squareThis x = x * x
let addFive x = x + 5
5 |> squareThis |> addFive yields 30
let squareAndAddFive = squareThis >> addFive
squareThisAndAddFive 5 yields 30
let shift (dx, dy) (px, py) = (px + dx, py + dy)
shift (1, 0) (100, 100) result is (101, 100)
let shiftRight = shift (1, 0)
shiftRight (100, 100) result is (101, 100)
Keep a lookaside table of computed values
let rec fib n = if n <= 2 then 1 else fib(n‐1) + fib(n‐2)
Computed values wasted Why not cache them?
let fibFast n = let t = new Dictionary<int,int>() let rec fibCached n = if t.ContainsKey(n) then t.[n] else if n <= 2 then 1 else let res = fibCached(n‐1) + fibCached(n‐2) t.Add(n,res) res fibCached n
Computation expressions = workflows builder { expression }
Usage General programming (e.g., seq { … }) Asynchronous workflows Database queries
Define a builder type Computation expression constructs map onto
the builder methods (are de-sugared) E.g., let a = b in c maps onto builder.Let(b, (fun a ‐> c))
Builder affects behavior of contained expressions E.g., makes them asynchronous
Many .NET APIs feature Begin/End pairs E.g., BeginGetResponse/EndGetResponse
Frameworks make code look sequential Abstracting away Begin/End calls C# AsyncEnumerator from PowerThreading F# Async workflows
Goals Begin an asynchronous operation Resume execution when it’s done Let threads interleave
Async<'a> Represents a result of 'a computed in the future
This class needs to know about begin/end pairs Extends existing types with XXXAsync() calls type WebRequest with
member x.GetResponseAsync() = Async.BuildPrimitive( x.BeginGetResponse, x.EndGetResponse)
Once Async knows about Begin/End elements we can use the async { … } workflow let download url =
async { let rq = WebRequest.Create(url) let! resp = rq.GetResponseAsync() use s = resp.GetResponseStram() use r = new StreamReader(s) r.ReadToEnd() }
let! fires off BeginGetResponse() asynchronously and waits on completion
let urls = [ “http://spbalt.net”; “http://sp.ineta.ru”; “http://altdotnet.org” ]
Spawn one-by-one for url in urls do
Async.Spawn(download(url))
Send all at once urls |> List.map(fun f ‐> download(f))
|> Async.Parallel |> Async.Run
Foundations of F# Robert Pickering
Expert F# Don Syme et al.
F# for Scientists Jon Harrop