class: center, middle # F\# – Surviving in .NET by [@gimpf](http://gimpf.org) for [r³](http://realraum.at) .smallBottomLeft[[under CC-BY](http://creativecommons.org/licenses/by/3.0/), (created with [remark](https://github.com/gnab/remark))] --- layout: true # Why F# at all? --- ## I searched because … - I hate typing. - as in "with fingers and keyboard" - especially the same thing all over again (class names) - I *love* descriptive names. - as in "doThisAndThatAndAbbreviationsAreOut" - I must use .NET - (that's actually not so bad!) --- ## (Thinking) How to type less without gooifying variable names? -- *Concise* programming languages: - type system that helps you - functional composition F# allows that. It can do more. --- layout: false # What I will talk about … * Preliminaries - Why might you be interested? - What you might get out of this intro. * Language Characteristics in Examples - Programming styles - Types - Type Providers - Computation Expressions --- # Teaser type WorldBank = WorldBankDataProvider<"World Development Indicators"> let data = WorldBank.GetDataContext() let r2 = data.Countries |> Seq.filter (fun x -> not << Seq.isEmpty <| x.Indicators .``Physicians (per 1,000 people)``) |> Seq.maxBy (fun x -> x.Indicators .``Physicians (per 1,000 people)`` |> Seq.maxBy snd) printfn "%A" r2 .pushdown[ [FSharp.Data Doc](http://tpetricek.github.com/FSharp.Data/docs/WorldBank.html) ] --- # Why might you be interested? .pushdown[ * You work on .NET/Mono, or want to. ] -- * You are using R, and require some serious programming-workhorse for stuff around it. * You would like to learn functional programming for fun, - but also use it in your job. .pushdown[ (does not apply to almost all r³ members) ] --- # What you should know - some real-life programming - that "Functional Programming" exists -- .pushdown[ # What you might get out of this - know how F# looks like - able to read most F# code - know if it is interesting enough to invest some time ] --- layout: true # 5 Minute Syntax --- ## Hello, World! printfn "Hello, World!" Like in not-Java! --- ## Code: Hello, %s! let greetee = "World" printfn "Hello, %s!" greetee -- BTW, this would not compile: printfn "Hello, %d!" greetee --- # Functions // does something let addOne x = x + 1 (* What would (* happen *) here? *) addOne 1.0 -- .output[ val addOne : x:int -> int addOne 1. -------^^ stdin(12,8): error FS0001: This expression was expected to have type int but here has type float ] --- # Integers and Floating Points let addOne x = x + 1. -- .output[ val addOne : x:float -> float ] --- layout: false class: center middle # Language Characteristics --- # Functional-First … (Almost) Everything is an expression. let a = if someThing = 3 then "Moi!" else "Muh." -- First-Class Functions let that = (fun x -> x + 2.) -- Operators are functions let that = ((+) 2.) --- layout: true # Functional-First cont'd --- Currying let add x y = x + y let inc = add 1 inc 4 .output[ 5 ] --- Higher Order Functions let sub x y = x - y let swapArg f x y = f y x let dec = swapArg sub 1 dec 4 .output[ 3 ] --- Composition List.empty |> (not << Seq.isEmpty) .output[ false ] --- Immutable by default let a = 3 do let a = 2 in () printfn "%A" a .output[ 3 ] -- .breaker[ let a = List.empty do let a = 1 :: a in () printfn "%A" a ] .output[ [] ] --- Mutable variables allowed let mutable a = 1 do a <- 2 printfn "%A" a .output[ 2 ] * It's still not Haskell. * .NET/F# ship with many immutable collections * Mutable versions _usually_ perform better. --- Tail-Call Elimination (starting with non-tail-call version) let rec foo n = match n with | 0 -> 0 | _ -> 2 + foo (n-1) Not Tail-Recursive because the return value of the recursive invocation is not the final result. --- Simple Tail-Recursive Version let rec bar acc n = match n with | 0 -> acc | _ -> bar (acc+2) (n-1) All arguments are evaluated before the recursive call. `acc` contains the result. .pushdown[ [example from @Batibix](http://stackoverflow.com/a/3248401/15529) ] --- layout: false # … but Multi-Paradigmatic: Imperative - Use modules and functions and - mutable values - for and while loops .breaker[ let array = Array.zeroCreate 16 for i in 0 .. 3 .. 15 do array.[i] <- (i+1) * 2 for element in array do printfn "%d" element ] --- # Object-Oriented Interfaces type IFooable = abstract member Foo : unit -> unit -- Classes type Foo (msg : string) = interface IFooable with member this.Foo() = printfn "%s" msg -- Inheritance type Bar () = inherit Foo("bar") --- # Object-Oriented Object Expressions { new Object() with override this.ToString() = "baz" } -- *Both upcast and downcast are explicit!* (Foo("foo") :> IFooable).Foo() --- # Meta-Programming Limited, but it is there. - Quoted Expressions - Syntax Sugar for Computation Expressions (Monads) - Reflection through .NET --- # Code Quotation let addExpr = <@ 1 + 1 @> let splicedExpr = <@ 2 * %addExpr @> printfn "%A" splicedExpr .output[ Call (None, op_Multiply, [ Value (2), Call (None, op_Addition, [ Value (1), Value (1)])]) ] --- # Computation Expressions let a = seq { for i in 0 .. 2 .. 100 do yield (float)i ** 2. } .output[ val a : seq
] This is a lazy list, representing a computation. .breaker[ a |> Array.ofSeq ] Microsoft's [Computation Expression documentation](http://msdn.microsoft.com/en-us/library/dd233182.aspx) is actually quite OK. --- # Async Monad .breaker[ let asyncHttpGet (url:string) = async { let req = WebRequest.Create(url) let! rsp = req.AsyncGetResponse() use stream = rsp.GetResponseStream() use reader = new StreamReader(stream) return reader.ReadToEnd() } [ asyncHttpGet "http://www.live.com" ; asyncHttpGet "http://www.google.com" ] |> Async.Parallel |> Async.RunSynchronously ] [Example from @dsyme](http://blogs.msdn.com/b/dsyme/archive/2007/10/11/introducing-f-asynchronous-workflows.aspx) --- # Query Monad Implementing the F# version of C#'s Linq requires ... an F# library. (Of course part of F# 3.0.) type Northwind = ODataService<"http://.../Northwind.svc"> let db = Northwind.GetDataContext() query { for customer in db.Customers do select (customer.ContactName, customer.Phone) } |> Seq.iter (printfn "%A") --- # Query Monad cont'd - Static types within the `query{}` - `query` monad converts to `IQueryable<'T>` calls - `ODataService` type-provider generated code that, upon execution (triggered by `Seq.iter`) calls the Web-service and does stuff. [Example from MSDN](http://msdn.microsoft.com/en-us/library/hh225374.aspx) --- class: middle center # Language Characteristic Summary --- # Programming Styles - Functional - Object-Oriented - Procedural - Meta-Programming --- # Typing * Strong Typing - type-correct access is enforced - no bit is ever reinterpreted - no raw memory access (except through `unsafe` P/Invoke) * Strict Types - no automatic conversion – at all! * Static Typing - types must be resolved at compile time --- # Convenience * Automatic Type Deduction in Hindley-Milner style * Garbage Collected - but no C++/D style RAII - instead non-memory resource collection aided through `use` of `IDisposable` .breaker[ use someThing = instantiateDisposable () // IDisposable.Dispose called // when leaving scope ] --- # Misc * Eager Evaluation - like ML, OCaml, Scheme - and absolutely not like Haskell * .NET-style object orientation - single implementation inheritence - multiple interface inheritance - single-dispatch dynamic polymorphism - static overloading * .NET-style Runtime Reflection - type inspection - IL generation --- # Syntax * OCaml was starting point for syntax. * whitespace-significant by default - like Python * Operator overloading. On steroids. (Haven't covered that yet...) --- # VM Characteristics * .NET VM is stable and fast - as compared to Python, Perl, Ruby, aaaand... Java * Generational, Incremental, and mostly Concurrent GC with per-thread fragments for major platforms - yes, even on [Mono](http://www.mono-project.com/Generational_GC) * No Global Interpreter Lock. --- # About Morality... * Mono is Open Source - and works, including base library * F# Compiler and Core is Open Source * Most F# specific libraries also Open Source At least better than Java, _and_ it is getting better. --- # Type Deduction * Top to Bottom * Left to Right * Single-Pass! No bottom-up, except: - Function argument types can be derived from function body - Function return type too - (probably some stuff I don't know) * Also derives type arguments! --- # Types * Numbers - int (unsigned and signed, from 8 to 64 bits) - floating point (32, 64 bits) - BigInt - BigRational * Text - characters (Unicode code point) - strings (character arrays with Sambal Oelek) --- # Types cont'd * Aggregates - records `{ name : type ; ... }` - tuples `( item1, item2, ...)` - lists `[ item1, item2, ...]` - arrays `[| item1, item2, ...|]` * .NET OO Types - interfaces - classes --- # Type Deduction Example .breaker[ let intList = [ 1 ; 2 ; 3 ] let stringList = [ "Hello," ; "World!" ] let doSomething f = intList @ (stringList |> Seq.map f |> Seq.toList) ] .output[ val intList : int list = [1; 2; 3] val stringList : string list = ["Hello,"; "World!"] val doSomething : f:(string -> int) -> int list ] --- # Type Deduction Failure (1/2) open System.Linq type SomeClass (name : string) = member x.Name = name let someArray = [| SomeClass("moi") |] someArray .All(fun x -> x.Name = "moi") someArray.AsQueryable() .All(fun x -> x.Name = "moi") --- # Type Deduction Failure (2/2) .output[ someArray.AsQueryable() .All(fun x -> x.Name = "moi") ----------------^^^^^^ stdin(57,17): error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. ] --- # Automatic Generalization .breaker[ let me = "Me" let transformMe f = f me ] .output[ val me : string = "Me" val transformMe : f:(string -> 'a) -> 'a ] --- # Next: * Destructuring bind * Pattern Matching --- # Destructuring Bind type S = { a : int ; b : float } let foo = [ (1 , { a = 5 ; b = 5.5 }) ; (2, { a = 4 ; b = 4.4 }) ] let [(x, _) ; (_, { b = y })] = foo printfn "x = %d ; y = %f" x y .output[ warning: Incomplete pattern matches… x = 1 ; y = 4.400000 ] --- # Destructuring Bind cont'd * Works in let bindings * Works in argument bindings * Works in pattern bindings Everywhere. --- # Pattern Matching Full ML-style pattern matching available. type Person = { name : string } type Employee = | Engineer of Person | Manager of Person * Employee list let p = {name="e"} let m = Manager({name="m"}, [ Engineer(p) ]) match m with | Engineer(e) -> printfn "%s" e.name | Manager(m, e) -> printfn "%s: { %A }" m.name e .output[ m: { [Engineer {name = "e";}] } ] --- # Caveats * Ambigous overloads on member functions ruin the type-deduction experience. * Automatic generalization and currying not always work together. * More convenient code is usually slower (but not excessively so). --- # We only scratched the surface. operator overloads, operator definitions, writing monads, writing type-providers, inline functions, active patterns, patterns guards, custom literals, arbitrary precision math, units of measure, literate F#, … I even forgot to mention exceptions. Oh my. --- class: references # Online Resources - [Try F# Online](http://www.tryfsharp.org/) - [F# Snippets](http://fssnip.net/) - [F# Software Foundation](http://fsharp.org/) - [F# Github Community](http://fsharp.github.com/) - [Literate F#](http://tomasp.net/blog/fsharp-literate-programming.aspx) - [Hindley-Milner (Wikipedia)](http://en.wikipedia.org/wiki/Hindley%E2%80%93Milner) - [FSharp.Data Doc](http://tpetricek.github.com/FSharp.Data/docs/WorldBank.html) - [SO F# Tail-Call Example](http://stackoverflow.com/questions/3248091/f-tail-recursive-function-example) - [async Example from @dsyme](http://blogs.msdn.com/b/dsyme/archive/2007/10/11/introducing-f-asynchronous-workflows.aspx) - [Computation Expressions](http://msdn.microsoft.com/en-us/library/dd233182.aspx)