5. Multi-paradigm language in .NET stack
Functional
Imperative
Performance similar to C#
Interactive console
Support in Visual Studio
Debugger
Editor
Mono support
6. #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
7. 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”
8. Can do it with a function
let sayHello =
printfn “Hello, F#!”
sayHello
Or pass a parameter
let sayHello s =
printfn s
sayHello "Hello, F#!"
9. 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
10. 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)
11. 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
12. 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
14. 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 ;
15. 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”
16. Your typical CLR array
let people = [|
“john”;
“jane”;
“jack”
|]
people.Length
yields 3
17. 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
18. 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:)
19. 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]
20. 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
21. A non-exhaustive match will throw a
MatchFailureException
Patterns can be grouped
match person with
| a :: (b :: c as subGroup) ‐>
match subGroup with
23. 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
24. 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
25. 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]
26. let squareThis x =
x * x
let addFive x =
x + 5
5 |> squareThis |> addFive
yields 30
let squareAndAddFive =
squareThis >> addFive
squareThisAndAddFive 5
yields 30
27. 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)
28. 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?
29. 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
31. 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
32. 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
33. 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)
34. 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
35. 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
36. Foundations of F#
Robert Pickering
Expert F#
Don Syme et al.
F# for Scientists
Jon Harrop