diff options
Diffstat (limited to 'fsharp.html.markdown')
| -rw-r--r-- | fsharp.html.markdown | 251 | 
1 files changed, 226 insertions, 25 deletions
| diff --git a/fsharp.html.markdown b/fsharp.html.markdown index 5c54130d..1deaf437 100644 --- a/fsharp.html.markdown +++ b/fsharp.html.markdown @@ -6,11 +6,11 @@ author_url: http://fsharpforfunandprofit.com/  F# is a general purpose functional/OO programming language.  It's free and open source, and runs on Linux, Mac, Windows and more.  -It has a powerful type system that traps many errors at compile time, but it uses type inference so that it read more like a dynamic language. +It has a powerful type system that traps many errors at compile time, but it uses type inference so that it reads more like a dynamic language. -The syntax of F# is similar to Python: +The syntax of F# is different from C-style languages: -* Curly braces are not used to delimit blocks of code. Instead, indentation is used. +* Curly braces are not used to delimit blocks of code. Instead, indentation is used (like Python).  * Whitespace is used to separate parameters rather than commas.  If you want to try out the code below, you can go to [tryfsharp.org](http://www.tryfsharp.org/Create) and paste it into an interactive REPL. @@ -123,7 +123,7 @@ printfn "A string %s, and something generic %A" "hello" [1;2;3;4]  // Modules are used to group functions together  // Indentation is needed for each nested module. -module Addition =  +module FunctionExamples =       // define a simple adding function      let add x y = x + y @@ -132,12 +132,12 @@ module Addition =      let a = add 1 2      printfn "1+2 = %i" a -    // partial application +    // partial application to "bake in" parameters      let add42 = add 42      let b = add42 1      printfn "42+1 = %i" b -    // composition +    // composition to combine functions      let add1 = add 1      let add2 = add 2      let add3 = add1 >> add2 @@ -153,40 +153,177 @@ module Addition =      printfn "1+2+3+7 = %i" d  // ================================================ -// Data Types  +// Lists and collection  // ================================================ +// There are three types of ordered collection: +// * Lists are most basic immutable collection.  +// * Arrays are mutable and more efficient when needed.  +// * Sequences are lazy and infinite (e.g. an enumerator).  +// +// Other collections include immutable maps and sets +// plus all the standard .NET collections + +module ListExamples =  + +    // lists use square brackets  +    let list1 = ["a";"b"] +    let list2 = "c" :: list1    // :: is prepending +    let list3 = list1 @ list2   // @ is concat +     +    // list comprehensions (aka generators) +    let squares = [for i in 1..10 do yield i*i]  + +    // prime number generator +    let rec sieve = function +        | (p::xs) -> p :: sieve [ for x in xs do if x % p > 0 then yield x ] +        | []      -> [] +    let primes = sieve [2..50] +    printfn "%A" primes  +     +    // pattern matching for lists +    let listMatcher aList =  +        match aList with +        | [] -> printfn "the list is empty"  +        | [first] -> printfn "the list has one element %A " first  +        | [first; second] -> printfn "list is %A and %A" first second  +        | _ -> printfn "the list has more than two elements"     + +    listMatcher [1;2;3;4] +    listMatcher [1;2] +    listMatcher [1] +    listMatcher []         + +    // recursion using lists +    let rec sum aList =  +        match aList with +        | [] -> 0 +        | x::xs -> x + sum xs +    sum [1..10] +     +    // -----------------------------------------     +    // Standard library functions  +    // ----------------------------------------- +     +    // map +    let add3 x = x + 3 +    [1..10] |> List.map add3 + +    // filter +    let even x = x % 2 = 0 +    [1..10] |> List.filter even +     +    // many more -- see documentation +     +module ArrayExamples =  + +    // arrays use square brackets with bar +    let array1 = [| "a";"b" |] +    let first = array1.[0]        // indexed access using dot +    +    // pattern matching for arrays is same as for lists +    let arrayMatcher aList =  +        match aList with +        | [| |] -> printfn "the array is empty"  +        | [| first |] -> printfn "the array has one element %A " first  +        | [| first; second |] -> printfn "array is %A and %A" first second  +        | _ -> printfn "the array has more than two elements"     + +    arrayMatcher [| 1;2;3;4 |] + +    // Standard library functions just as for List +    +    [| 1..10 |]  +    |> Array.map (fun i -> i+3) +    |> Array.filter (fun i -> i%2 = 0) +    |> Array.iter (printfn "value is %i. ") +     +     +module SequenceExamples =  + +    // sequences use curly braces +    let seq1 = seq { yield "a"; yield "b" } +     +    // sequences can use yield and  +    // can contain subsequences +    let strange = seq { +        // "yield! adds one element +        yield 1; yield 2; +         +        // "yield!" adds a whole subsequence +        yield! [5..10]   +        yield! seq { +            for i in 1..10 do  +              if i%2 = 0 then yield i }} +    // test                 +    strange |> Seq.toList               +               + +    // Sequences can be created using "unfold" +    // Here's the fibonacci series +    let fib = Seq.unfold (fun (fst,snd) -> +        Some(fst + snd, (snd, fst + snd))) (0,1) + +    // test                         +    let fib10 = fib |> Seq.take 10 |> Seq.toList +    printf "first 10 fibs are %A" fib10      +    +     +// ================================================ +// Data Types  +// ================================================  module DataTypeExamples =       // All data is immutable by default      // Tuples are quick 'n easy anonymous types +    // -- Use a comma to create a tuple      let twoTuple = 1,2      let threeTuple = "a",2,true +     +    // Pattern match to unpack +    let x,y = twoTuple  //sets x=1 y=2 -    // Record types have named fields +    // ------------------------------------  +    // Record types have named fields  +    // ------------------------------------  + +    // Use "type" with curly braces to define a record type      type Person = {First:string; Last:string} -    let person1 = {First="john"; Last="Doe"} +     +    // Use "let" with curly braces to create a record  +    let person1 = {First="John"; Last="Doe"} +    // Pattern match to unpack +    let {First=first} = person1    //sets first="john" + +    // ------------------------------------       // Union types (aka variants) have a set of choices      // Only case can be valid at a time. +    // ------------------------------------  + +    // Use "type" with bar/pipe to define a union type      type Temp =           | DegreesC of float          | DegreesF of float +         +    // Use one of the cases to create one      let temp1 = DegreesF 98.6      let temp2 = DegreesC 37.0 -    // Union types are great for modelling state without using flags -    type EmailAddress =  -        | ValidEmailAddress of string -        | InvalidEmailAddress of string +    // Pattern match on all cases to unpack +    let printTemp = function +       | DegreesC t -> printfn "%f degC" t +       | DegreesF t -> printfn "%f degF" t +     +    printTemp temp1  +    printTemp temp2 + +    // ------------------------------------  +    // Recursive types +    // ------------------------------------  -    let trySendEmail email = -        match email with // use pattern matching -        | ValidEmailAddress address -> ()   // send -        | InvalidEmailAddress address -> () // dont send -              // Types can be combined recursively in complex ways       // without having to create subclasses      type Employee =  @@ -195,6 +332,20 @@ module DataTypeExamples =      let jdoe = {First="John";Last="Doe"}      let worker = Worker jdoe +     +    // ------------------------------------  +    // Modelling with types +    // ------------------------------------  +     +    // Union types are great for modelling state without using flags +    type EmailAddress =  +        | ValidEmailAddress of string +        | InvalidEmailAddress of string + +    let trySendEmail email = +        match email with // use pattern matching +        | ValidEmailAddress address -> ()   // send +        | InvalidEmailAddress address -> () // dont send      // The combination of union types and record types together      // provide a great foundation for domain driven design. @@ -211,10 +362,35 @@ module DataTypeExamples =          | ActiveCart of ActiveCartData          | PaidCart of PaidCartData     -    // All complex types have pretty printing built in for free +    // ------------------------------------  +    // Built in behavior for types +    // ------------------------------------  + +    // Core types have useful "out-of-the-box" behavior, no coding needed. +    // * Immutability +    // * Pretty printing when debugging +    // * Equality and comparison +    // * Serialization +         +    // Pretty printing using %A      printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A"                twoTuple person1 temp1 worker -          + +    // Equality and comparison built in. +    // Here's an example with cards. +    type Suit = Club | Diamond | Spade | Heart +    type Rank = Two | Three | Four | Five | Six | Seven | Eight  +                | Nine | Ten | Jack | Queen | King | Ace     + +    let hand = [ Club,Ace; Heart,Three; Heart,Ace;  +                 Spade,Jack; Diamond,Two; Diamond,Ace ] + +    // sorting +    List.sort hand |> printfn "sorted hand is (low to high) %A" +    List.max hand |> printfn "high card is %A" +    List.min hand |> printfn "low card is %A" + +               // ================================================  // Active patterns  // ================================================ @@ -224,6 +400,8 @@ module ActivePatternExamples =      // F# has a special type of pattern matching called "active patterns"       // where the pattern can be parsed or detected dynamically.  +    // "banana clips" are the syntax for active patterns +          // for example, define an "active" pattern to match character types...      let (|Digit|Letter|Whitespace|Other|) ch =          if System.Char.IsDigit(ch) then Digit @@ -242,7 +420,26 @@ module ActivePatternExamples =      // print a list      ['a';'b';'1';' ';'-';'c'] |> List.iter printChar -    +    // ----------------------------------- +    // FizzBuzz using active patterns +    // ----------------------------------- +     +    // You can create partial matching patterns as well +    // Just use undercore in the defintion, and return Some if matched. +    let (|MultOf3|_|) i = if i % 3 = 0 then Some MultOf3 else None +    let (|MultOf5|_|) i = if i % 5 = 0 then Some MultOf5 else None + +    // the main function +    let fizzBuzz i =  +      match i with +      | MultOf3 & MultOf5 -> printf "FizzBuzz, "  +      | MultOf3 -> printf "Fizz, "  +      | MultOf5 -> printf "Buzz, "  +      | _ -> printf "%i, " i +       +    // test +    [1..20] |> List.iter fizzBuzz  +      // ================================================  // Conciseness   // ================================================ @@ -289,7 +486,7 @@ module AlgorithmExamples =  module AsyncExample =  -    // F# has some built-in features to help with async code +    // F# has built-in features to help with async code      // without encountering the "pyramid of doom"      //      // The following example downloads a set of web pages in parallel. @@ -301,10 +498,14 @@ module AsyncExample =      // Fetch the contents of a URL asynchronously      let fetchUrlAsync url =         -        async {                              +        async {   // "async" keyword and curly braces  +                  // creates an "async" object              let req = WebRequest.Create(Uri(url))  -            use! resp = req.AsyncGetResponse()   +            use! resp = req.AsyncGetResponse()     +                // use! is async assignment              use stream = resp.GetResponseStream()  +                // "use" triggers automatic close() +                // on resource at end of scope              use reader = new IO.StreamReader(stream)               let html = reader.ReadToEnd()               printfn "finished downloading %s" url  @@ -360,7 +561,7 @@ module NetCompatibilityExamples =      // F# is also a fully fledged OO language.      // It supports classes, inheritance, virtual methods, etc. -    // interface +    // interface with generic type      type IEnumerator<'a> =           abstract member Current : 'a          abstract MoveNext : unit -> bool  | 
