Sei sulla pagina 1di 37

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

Potrebbero piacerti anche