diff options
Diffstat (limited to 'fsharp.html.markdown')
| -rw-r--r-- | fsharp.html.markdown | 431 | 
1 files changed, 431 insertions, 0 deletions
| diff --git a/fsharp.html.markdown b/fsharp.html.markdown new file mode 100644 index 00000000..69c70bc6 --- /dev/null +++ b/fsharp.html.markdown @@ -0,0 +1,431 @@ +--- +language: F# +author: Scott Wlaschin +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. + +The syntax of F# is similar to Python: + +* Curly braces are not used to delimit blocks of code. Instead, indentation is used. +* 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. + +```fsharp + +// single line comments use a double slash +(* multi line comments use (* . . . *) pair + +-end of multi line comment- *) + +// ================================================ +// Basic Syntax +// ================================================ + +// ------ "Variables" (but not really) ------ +// The "let" keyword defines an (immutable) value +let myInt = 5 +let myFloat = 3.14 +let myString = "hello"           //note that no types needed + +// ------ Lists ------ +let twoToFive = [2;3;4;5]        // Square brackets create a list with +                                 // semicolon delimiters. +let oneToFive = 1 :: twoToFive   // :: creates list with new 1st element +// The result is [1;2;3;4;5] +let zeroToFive = [0;1] @ twoToFive   // @ concats two lists + +// IMPORTANT: commas are never used as delimiters, only semicolons! + +// ------ Functions ------ +// The "let" keyword also defines a named function. +let square x = x * x          // Note that no parens are used. +square 3                      // Now run the function. Again, no parens. + +let add x y = x + y           // don't use add (x,y)! It means something +                              // completely different. +add 2 3                       // Now run the function. + +// to define a multiline function, just use indents. No semicolons needed. +let evens list = +   let isEven x = x%2 = 0     // Define "isEven" as a sub function +   List.filter isEven list    // List.filter is a library function +                              // with two parameters: a boolean function +                              // and a list to work on + +evens oneToFive               // Now run the function + +// You can use parens to clarify precedence. In this example, +// do "map" first, with two args, then do "sum" on the result. +// Without the parens, "List.map" would be passed as an arg to List.sum +let sumOfSquaresTo100 = +   List.sum ( List.map square [1..100] ) + +// You can pipe the output of one operation to the next using "|>" +// Piping data around is very common in F#, similar to UNIX pipes. + +// Here is the same sumOfSquares function written using pipes +let sumOfSquaresTo100piped = +   [1..100] |> List.map square |> List.sum  // "square" was defined earlier + +// you can define lambdas (anonymous functions) using the "fun" keyword +let sumOfSquaresTo100withFun = +   [1..100] |> List.map (fun x -> x*x) |> List.sum + +// In F# there is no "return" keyword. A function always +// returns the value of the last expression used. + +// ------ Pattern Matching ------ +// Match..with.. is a supercharged case/switch statement. +let simplePatternMatch = +   let x = "a" +   match x with +    | "a" -> printfn "x is a" +    | "b" -> printfn "x is b" +    | _ -> printfn "x is something else"   // underscore matches anything + +// F# doesn't allow nulls by default -- you must use an Option type +// and then pattern match.   +// Some(..) and None are roughly analogous to Nullable wrappers +let validValue = Some(99) +let invalidValue = None + +// In this example, match..with matches the "Some" and the "None", +// and also unpacks the value in the "Some" at the same time. +let optionPatternMatch input = +   match input with +    | Some i -> printfn "input is an int=%d" i +    | None -> printfn "input is missing" + +optionPatternMatch validValue +optionPatternMatch invalidValue + +// ------ Printing ------ +// The printf/printfn functions are similar to the +// Console.Write/WriteLine functions in C#. +printfn "Printing an int %i, a float %f, a bool %b" 1 2.0 true +printfn "A string %s, and something generic %A" "hello" [1;2;3;4] + +// There are also sprintf/sprintfn functions for formatting data +// into a string, similar to String.Format in C#. + +// ================================================ +// More on functions  +// ================================================ + +// F# is a true functional language -- functions are first +// class entities and can be combined easy to make powerful +// constructs + +// Modules are used to group functions together +// Indentation is needed for each nested module. +module Addition =  + +    // define a simple adding function +    let add x y = x + y +     +    // basic usage of a function +    let a = add 1 2 +    printfn "1+2 = %i" a +     +    // partial application +    let add42 = add 42 +    let b = add42 1 +    printfn "42+1 = %i" b +     +    // composition +    let add1 = add 1 +    let add2 = add 2 +    let add3 = add1 >> add2 +    let c = add3 7 +    printfn "3+7 = %i" c +     +    // higher order functions +    [1..10] |> List.map add3 |> printfn "new list is %A" +     +    // lists of functions, and more +    let add6 = [add1; add2; add3] |> List.reduce (>>) +    let d = add6 7 +    printfn "1+2+3+7 = %i" d + +// ================================================ +// Data Types  +// ================================================ + + +module DataTypeExamples =  + +    // All data is immutable by default + +    // Tuples are quick 'n easy anonymous types +    let twoTuple = 1,2 +    let threeTuple = "a",2,true + +    // Record types have named fields +    type Person = {First:string; Last:string} +    let person1 = {First="john"; Last="Doe"} + +    // Union types (aka variants) have a set of choices +    // Only case can be valid at a time. +    type Temp =  +        | DegreesC of float +        | DegreesF of float +    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 + +    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 =  +      | Worker of Person +      | Manager of Employee list + +    let jdoe = {First="John";Last="Doe"} +    let worker = Worker jdoe + +    // The combination of union types and record types together +    // provide a great foundation for domain driven design. +    // You can create hundreds of little types that accurately  +    // reflect the domain. + +    type CartItem = { ProductCode: string; Qty: int } +    type Payment = Payment of float +    type ActiveCartData = { UnpaidItems: CartItem list } +    type PaidCartData = { PaidItems: CartItem list; Payment: Payment} +         +    type ShoppingCart =  +        | EmptyCart  // no data +        | ActiveCart of ActiveCartData +        | PaidCart of PaidCartData     + +    // All complex types have pretty printing built in for free +    printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A"  +             twoTuple person1 temp1 worker +          +// ================================================ +// Active patterns +// ================================================ + +module ActivePatternExamples =  + +    // F# has a special type of pattern matching called "active patterns"  +    // where the pattern can be parsed or detected dynamically.  + +    // for example, define an "active" pattern to match character types... +    let (|Digit|Letter|Whitespace|Other|) ch =  +       if System.Char.IsDigit(ch) then Digit +       else if System.Char.IsLetter(ch) then Letter +       else if System.Char.IsWhiteSpace(ch) then Whitespace +       else Other          + +    // ... and then use it to make parsing logic much clearer +    let printChar ch =  +      match ch with +      | Digit -> printfn "%c is a Digit" ch +      | Letter -> printfn "%c is a Letter" ch +      | Whitespace -> printfn "%c is a Whitespace" ch +      | _ -> printfn "%c is something else" ch + +    // print a list +    ['a';'b';'1';' ';'-';'c'] |> List.iter printChar + +    +// ================================================ +// Conciseness  +// ================================================ + +module AlgorithmExamples =  + +    // F# has a high signal/noise ratio, so code reads  +    // almost like the actual algorithm + +    // ------ Example: define sumOfSquares function ------ +    let sumOfSquares n =  +       [1..n]              // 1) take all the numbers from 1 to n +       |> List.map square  // 2) square each one +       |> List.sum         // 3) sum the results + +    // test    +    sumOfSquares 100 |> printfn "Sum of squares = %A"  +        +    // ------ Example: define a sort function ------   +    let rec sort list = +       match list with +       // If the list is empty    +       | [] ->                             +            []                            // return an empty list +       // If the list is not empty   +       | firstElem::otherElements ->      // take the first element     +            let smallerElements =         // extract the smaller elements     +                otherElements             // from the remaining ones +                |> List.filter (fun e -> e < firstElem)  +                |> sort                   // and sort them +            let largerElements =          // extract the larger ones +                otherElements             // from the remaining ones +                |> List.filter (fun e -> e >= firstElem) +                |> sort                   // and sort them +            // Combine the 3 parts into a new list and return it +            List.concat [smallerElements; [firstElem]; largerElements] + +    // test +    sort [1;5;23;18;9;1;3] |> printfn "Sorted = %A"  + +// ================================================ +// Asynchronous Code +// ================================================ + +module AsyncExample =  + +    // F# has some 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. + +    open System.Net +    open System +    open System.IO +    open Microsoft.FSharp.Control.CommonExtensions    + +    // Fetch the contents of a URL asynchronously +    let fetchUrlAsync url =         +        async {                              +            let req = WebRequest.Create(Uri(url))  +            use! resp = req.AsyncGetResponse()   +            use stream = resp.GetResponseStream()  +            use reader = new IO.StreamReader(stream)  +            let html = reader.ReadToEnd()  +            printfn "finished downloading %s" url  +            } +             +    // a list of sites to fetch +    let sites = ["http://www.bing.com"; +                 "http://www.google.com"; +                 "http://www.microsoft.com"; +                 "http://www.amazon.com"; +                 "http://www.yahoo.com"] + +    // do it +    sites  +    |> List.map fetchUrlAsync  // make a list of async tasks +    |> Async.Parallel          // set up the tasks to run in parallel +    |> Async.RunSynchronously  // start them off + +// ================================================ +// .NET compatability +// ================================================ + +module NetCompatibilityExamples =  + +    // F# can do almost everything C# can do, and it integrates +    // seamlessly with .NET or Mono libraries. + +    // ------- work with existing library functions  ------- +     +    let (i1success,i1) = System.Int32.TryParse("123"); +    if i1success then printfn "parsed as %i" i1 else printfn "parse failed" + +    // ------- Implement interfaces on the fly! ------- +     +    // create a new object that implements IDisposable +    let makeResource name =  +       { new System.IDisposable  +         with member this.Dispose() = printfn "%s disposed" name } + +    let useAndDisposeResources =  +        use r1 = makeResource "first resource" +        printfn "using first resource"  +        for i in [1..3] do +            let resourceName = sprintf "\tinner resource %d" i +            use temp = makeResource resourceName  +            printfn "\tdo something with %s" resourceName  +        use r2 = makeResource "second resource" +        printfn "using second resource"  +        printfn "done."  + +    // ------- Object oriented code ------- +     +    // F# is also a fully fledged OO language. +    // It supports classes, inheritance, virtual methods, etc. + +    // interface +    type IEnumerator<'a> =  +        abstract member Current : 'a +        abstract MoveNext : unit -> bool  + +    // abstract base class with virtual methods +    [<AbstractClass>] +    type Shape() =  +        //readonly properties +        abstract member Width : int with get +        abstract member Height : int with get +        //non-virtual method +        member this.BoundingArea = this.Height * this.Width +        //virtual method with base implementation +        abstract member Print : unit -> unit  +        default this.Print () = printfn "I'm a shape" + +    // concrete class that inherits from base class and overrides  +    type Rectangle(x:int, y:int) =  +        inherit Shape() +        override this.Width = x +        override this.Height = y +        override this.Print ()  = printfn "I'm a Rectangle" + +    //test +    let r = Rectangle(2,3) +    printfn "The width is %i" r.Width +    printfn "The area is %i" r.BoundingArea +    r.Print()         + +    // ------- extension methods  ------- +         +    //Just as in C#, F# can extend existing classes with extension methods. +    type System.String with +       member this.StartsWithA = this.StartsWith "A" + +    //test +    let s = "Alice" +    printfn "'%s' starts with an 'A' = %A" s s.StartsWithA     +     +    // ------- events  ------- +    +    type MyButton() = +        let clickEvent = new Event<_>() + +        [<CLIEvent>] +        member this.OnClick = clickEvent.Publish + +        member this.TestEvent(arg) = +            clickEvent.Trigger(this, arg) + +    // test +    let myButton = new MyButton() +    myButton.OnClick.Add(fun (sender, arg) ->  +            printfn "Click event with arg=%O" arg) + +    myButton.TestEvent("Hello World!") +         +``` + +## More Information + +For more demonstrations of F#, go to the [Try F#](http://www.tryfsharp.org/Learn) site, or my [why use F#](http://fsharpforfunandprofit.com/why-use-fsharp/) series. + +Read more about F# at [fsharp.org](http://fsharp.org/). + + + + | 
