[Faculty of Science Information and Computing Sciences] 1
Concepts of programming languages F# Tim Zoet, Zino Onomiwo, - - PowerPoint PPT Presentation
Concepts of programming languages F# Tim Zoet, Zino Onomiwo, - - PowerPoint PPT Presentation
[Faculty of Science Information and Computing Sciences] 1 Concepts of programming languages F# Tim Zoet, Zino Onomiwo, Martijn Boom, Rik van Toor [Faculty of Science Information and Computing Sciences] 2 Background Don Syme
[Faculty of Science Information and Computing Sciences] 2
Background
▶ Don Syme ▶ Microsoft Research ▶ Recent development by the F# Software Foundation ▶ Microsoft develops the Visual F# tools
[Faculty of Science Information and Computing Sciences] 3
What is F#
▶ A fjrst-class member of the .NET Framework. ▶ Strongly related to ML and OCaml. ▶ A hybrid language ▶ Integration within Visual Studio
[Faculty of Science Information and Computing Sciences] 4
Programming in F#
Hello World
let a_string = "World" printfn "Hello %s" a_string
[Faculty of Science Information and Computing Sciences] 5
Types and variables
type name = string let author: name = "infinite monkey" What features regarding types are supported in F#?
[Faculty of Science Information and Computing Sciences] 6
Tuples, structures and more.
Tuples:
type tuple = int * string let tuple = (1, “hi!”) // Comma separated
Records
type Person = {Name:string; Age:int; Status:string} // named fields, semicolon separated let celebrity = {Name=”Gordon”, Age=49, Status=”single”}
[Faculty of Science Information and Computing Sciences] 7
Tuples, structures and more.
Union
type Person = | CatPerson of string | DogPerson of string let martijn = DogPerson “Martijn”
[Faculty of Science Information and Computing Sciences] 8
Tuples, structures and more.
Recursive structures and unions:
type 'a union = A 'a | B 'a type 'a tree = |EmptyTree | Node of 'a * 'a tree * 'a tree
[Faculty of Science Information and Computing Sciences] 9
Tuples, structures and more.
Structures:
type Cat = struct val Name: name; val Fur: color val Env: environment new (n, f, e) = {Name = n; Fur = f; Env = e} end let cat: Cat = new Cat("Ottoman", RED, BLOCKCHAIN)
[Faculty of Science Information and Computing Sciences] 10
Lists and arrays
Arrays
Fixed size and mutable let arr = [|1; 2; 3; 4; 5|] let arr2 = [|1.0; 2; 3|] // Gives an error let arr3 = [|for i in 1 .. 100 -> i * (i+1)|] printfn “%d” arr.[0] // prints 2 printfn “%A” array // print [1; 2; 3; 4; 5]
[Faculty of Science Information and Computing Sciences] 11
Lists and arrays
Lists
singly linked list and immutable let lissy = [1; 2; 3] let lissy2= 1::[2 … 8999] @ [1] let lissy3= [for i in 1 .. 100 -> i * (i+1)] let rec sum list = match list with | head :: tail -> head + sum tail | [] -> 0
[Faculty of Science Information and Computing Sciences] 12
Functions
let add x y = x + y let sumOfSquares n = [1..n] |> List.map square |> List.sum sumOfSquares 100 let adderGenerator = fun x -> (fun y -> x + y)
[Faculty of Science Information and Computing Sciences] 13
Classes
type Exam(student, subject, grade) = member this.Student = student member this.Subject = subject member this.Grade = grade// public member let stressLevel = 100 //private member new Exam(“Socrates”, “Philosophy for dummies”, 10)
[Faculty of Science Information and Computing Sciences] 14
Pattern matching
match x with | case1 -> … | case2 -> … | _ -> …
[Faculty of Science Information and Computing Sciences] 15
let patternMatcher input = match input with | “a” -> printfn “Case 1” | “b” -> printfn “Case 2” | _
- > printfn “Default”
patternMatcher “a” patternMatcher “b” patternMatcher “c”
[Faculty of Science Information and Computing Sciences] 16
let listSummary list = match list with | []
- > printfn "empty array"
| [x]
- > printfn "one element: %s" x
| [x;y] -> printfn "two elements” | _
- > printfn "multiple elements"
[Faculty of Science Information and Computing Sciences] 17
Async
Ruin code in parallel let motivationLevel (lvl, target) = async { printfn "Motivating %s till %i \%" target lvl do! Async.Sleep percentage printfn "%s is %i \% motivated" target lvl } [(101, “Tim”), (65, “Rik”)] |> List.map motivationLevel |> Async.Parallel |> Async.RunSynchronously
[Faculty of Science Information and Computing Sciences] 18
[<Measure>] type cm [<Measure>] type meter let cmPerMeter = 10<cm/meter> let distanceToHomeCm = 100<cm> let distanceToHomeM = distanceToHomeCm * cmPerMeter let otherConvert v: float<_> = match v with | :? float<cm> -> v * cmPerMeter | :? float<meter> -> v<meter>
[Faculty of Science Information and Computing Sciences] 19
Type inference
▶ Using amas-Milner’s Algorithm ▶ Look at the literals ▶ Look at the functions and other values something interacts
with
▶ Look at any explicit type constraints ▶ If there are no constraints anywhere, automatically
generalize to generic types
[Faculty of Science Information and Computing Sciences] 20
Relation to other languages
[Faculty of Science Information and Computing Sciences] 21
Compared to C#
▶ Concise
public static IEnumerable<T> QuickSort<T>(this IEnumerable<T> values) where T: IComparable { if (values == null || !values.Any()) return new List<T>(); var pivot = values.First(); var rest = values.Skip(1); var smallerElements = rest.Where(i => i.CompareTo(pivot) < 0).QuickSort(); var largerElements = rest.Where(i => i.CompareTo(pivot) >= 0).QuickSort(); return smallerElements.Concat(new List<T> { pivot }).Concat(largerElements); }
[Faculty of Science Information and Computing Sciences] 22
let rec quicksort = function | [] -> [] | pivot::rest -> let smaller,larger = List.partition ((>=) pivot) rest List.concat [quicksort smaller; [pivot]; quicksort larger]
▶ Little coding noise ▶ Pattern matching ▶ Functional List module
[Faculty of Science Information and Computing Sciences] 23
Type inference
let AStringFunction = "It is implied I return a string" let AStringFunction :string = "It is made explicit I return a string" string AnotherStringFunction(){ return "I'm a string function as well"; }
[Faculty of Science Information and Computing Sciences] 24
Domain-driven design
type StreetAddress = {Line1:string; Line2:string; Line3:string } type ZipCode = ZipCode of string type StateAbbrev = StateAbbrev of string type ZipAndState = {State:StateAbbrev; Zip:ZipCode } type USAddress = {Street:StreetAddress; Region:ZipAndState} type UKPostCode = PostCode of string type UKAddress = {Street:StreetAddress; Region:UKPostCode}
[Faculty of Science Information and Computing Sciences] 25
Domain-driven design
type InternationalAddress = { Street:StreetAddress; Region:string; CountryName:string} type Address = USAddress | UKAddress | InternationalAddress
[Faculty of Science Information and Computing Sciences] 26
Interoperability with C#
namespace interoperability.fsharp type Beverage (brand:string, volume:int) = member this.Brand = brand member this.Volume = volume
[Faculty of Science Information and Computing Sciences] 27
using interoperability.fsharp; namespace interoperability.csharp { class Program { static void Main(string[] args) { //from record to class Beverage coke = new Beverage("Coca Cola", 330); Console.WriteLine(coke.name + “ “ + coke.Volume); } } }
[Faculty of Science Information and Computing Sciences] 28
using interoperability.fsharp; namespace interoperability.csharp { class Program { static void Main(string[] args) { //from record to class Beverage coke = new Beverage("Coca Cola", 330); Console.WriteLine(coke.name + “ “ + coke.Volume); } } }
▶ output = “Coca Cola 330”
[Faculty of Science Information and Computing Sciences] 29
namespace interoperability.fsharp type Beverage (brand:string, volume:int) = member this.Brand = brand member this.Volume = volume module BeverageTasks = let drink (x:Beverage) = Beverage(x.Brand, 0)
[Faculty of Science Information and Computing Sciences] 30
using interoperability.fsharp; namespace interoperability.csharp { class Program { static void Main(string[] args) { //from record to class Beverage coke = new Beverage("Coca Cola", 330); //from module to static class coke = BeverageTasks.drink(coke) Console.WriteLine(coke.name + “ “ + coke.Volume); } } }
[Faculty of Science Information and Computing Sciences] 31
using interoperability.fsharp; namespace interoperability.csharp { class Program { static void Main(string[] args) { //from record to class Beverage coke = new Beverage("Coca Cola", 330); //from module to static class coke = BeverageTasks.drink(coke); Console.WriteLine(coke.name + “ “ + coke.Volume); } } }
- utput = “Coca Cola 0”
[Faculty of Science Information and Computing Sciences] 32
namespace interoperability.fsharp type Beverage (brand:string, volume:int) = member this.Brand = brand member this.Volume = volume module BeverageTasks = let drink (x:Beverage) = Beverage(x.Brand, 0) let mutable message = "Wasn't I supposed to be functional?"
[Faculty of Science Information and Computing Sciences] 33
using interoperability.fsharp; namespace interoperability.csharp { class Program { static void Main(string[] args) { //from record to class Beverage coke = new Beverage("Coca Cola", 330); Console.WriteLine(BeverageTasks.message); BeverageTasks.message = "Not anymore!"; Console.WriteLine(BeverageTasks.message); } } }
[Faculty of Science Information and Computing Sciences] 34
using interoperability.fsharp; namespace interoperability.csharp { class Program { static void Main(string[] args) { //from record to class Beverage coke = new Beverage("Coca Cola", 330); Console.WriteLine(BeverageTasks.message); BeverageTasks.message = "Not anymore!"; Console.WriteLine(BeverageTasks.message); } } }
▶ “Wasn’t I supposed to be functional?” ▶ “Not anymore!”
[Faculty of Science Information and Computing Sciences] 35
type Taste = | Sweet = 'a' | Sour = 'b' | Bitter = 'c' | Salty = 'd' Taste cokeTaste = Taste.Sweet;
[Faculty of Science Information and Computing Sciences] 36
type Taste = | Sweet = 'a' | Sour = 'b' | Bitter = 'c' | Salty = 'd' Taste cokeTaste = Taste.Sweet;
▶ error = ‘Taste.Sweet’ is not supported by the language
[Faculty of Science Information and Computing Sciences] 37
Relation to Haskell
▶ Both are functional languages ▶ Both have cool logos ▶ Similar way of thinking while coding
[Faculty of Science Information and Computing Sciences] 38
Relation to Haskell
F#
▶ Functional fjrst
Haskell
▶ Purely functional
[Faculty of Science Information and Computing Sciences] 39
Polymorphism
F#
▶ Does not really exist
Haskell
▶ Exists
[Faculty of Science Information and Computing Sciences] 40
Polymorphism
Haskell (in GHCi):
> let square x = x * x > square 2 4 > square 2.0 4.0
[Faculty of Science Information and Computing Sciences] 41
Polymorphism
F# (in fsharpi):
> let square x = x * x;; > square 2;; val it : int = 4 > square 2.0;; error FS0001: This expression was expected to have type int Caused by Type Inference.
[Faculty of Science Information and Computing Sciences] 42
Polymorphism
To override: > let inline square x = x * x;; > square 2;; val it : int = 4 > square 2.0;; val it : float = 4.0
[Faculty of Science Information and Computing Sciences] 43
Polymorphism - More diffjcult
In Haskell: class Showable a where shw :: a -> String data A = A String data B = B Int instance Showable A where shw (A s) = s instance Showable B where shw (B i) = show i
[Faculty of Science Information and Computing Sciences] 44
Polymorphism - More diffjcult
In F#: type A = { thing: int } with static member show a = sprintf "%A" a type B = { label: string } with static member show b = sprintf "%A" b let inline show (x:^t) = (^t: (static member show: ^t -> string) (x)) This is called statically resolved type constraints
[Faculty of Science Information and Computing Sciences] 45
Polymorphism - More diffjcult
An alternative in F#: type A = { thing: int } type B = { label: string } type ThingThatShows = static member show(x:A) = sprintf "%A" x static member show(x:B) = sprintf "%A" x This is called static member overloading
[Faculty of Science Information and Computing Sciences] 46
Currying
Works the same way in F# and Haskell. let f a b = something is internally converted to let f a = let g b = something g
[Faculty of Science Information and Computing Sciences] 47
Currying
This also means that the type signature a -> b -> c is equal to a -> (b -> c) Just like it would be in Haskell.
[Faculty of Science Information and Computing Sciences] 48
Partial application
Consider f :: int -> int -> int. Because of the currying mechanism, f 2 will be of type int -> int. Partial applications works the same way in F# and Haskell.
[Faculty of Science Information and Computing Sciences] 49
Function associativity
x y z is equal to (x y) z. Just like in Haskell, function application is left associative. Operators exist to help: x <| y z is equal to x (y z), limiting the number of parentheses. The same operator but inverted exists as well: x y |> z is equal to z (x y).
[Faculty of Science Information and Computing Sciences] 50
Evaluation
Haskell uses lazy evaluation. F# uses eager evaluation by default, unless explicitly specifjed
- therwise.
Example: let always5 x = 5
[Faculty of Science Information and Computing Sciences] 51
Evaluation
Haskell:
- - Will just return 5
always5 $ map sqrt [1.0..1000000000.0] F#: //Will take a long time always5 <| List.map sqrt [1.0..1000000000.0] //Will just return 5 always5 <| lazy(List.map sqrt [1.0..1000000000.0])
[Faculty of Science Information and Computing Sciences] 52
Syntax
F#:
▶ A little more verbose than Haskell ▶ More keywords than Haskell
Haskell:
▶ Amazing ▶ The best
[Faculty of Science Information and Computing Sciences] 53
Syntax - examples
▶ let let let let let let let let let let let let let. ▶ You will type let a lot in F#.
[Faculty of Science Information and Computing Sciences] 54
Syntax - examples
F#
let rec sum list = match list with | head :: tail -> head + sum tail | [] -> 0
Haskell
sum [] = 0 sum (head:tail) = head + sum tail
▶ Explicit rec
[Faculty of Science Information and Computing Sciences] 55
Type providers
‘Information-rich programming’
[Faculty of Science Information and Computing Sciences] 56
Making programming as easy as possible.
[Faculty of Science Information and Computing Sciences] 57
Coincidentally the subject of our research project.
[Faculty of Science Information and Computing Sciences] 58
▶ Generate types and add them to your project based on
some source containing type defjnitions.
▶ Type checking. ▶ Auto-completion. ▶ Integrated connection handling.
[Faculty of Science Information and Computing Sciences] 59
Improvement on:
▶ Manual implementation ▶ Code generation ▶ (Runtime generation)
[Faculty of Science Information and Computing Sciences] 60
Manual implementation
▶ Write F# type for every type in your information space.
[Faculty of Science Information and Computing Sciences] 61
Manual implementation
▶ Updates of information space? Manual work… ▶ Not doable in real world applications with thousands of
types.
[Faculty of Science Information and Computing Sciences] 62
Code generation
▶ Generate F# types from e.g. a fjle containing type
defjnitions.
[Faculty of Science Information and Computing Sciences] 63
Code generation
▶ Rerun when information space changes.
[Faculty of Science Information and Computing Sciences] 64
Example CSV
name age length Alice 42 1.69 Bob 24 1.78 Eve 32 1.75 … … …
[Faculty of Science Information and Computing Sciences] 65
type UserFile = CsvProvider<"someFile.csv"> let userFileInstance = UserFile.Load("sameOrMaybeAnotherFile.csv") print userFileInstance.firstRow.name
[Faculty of Science Information and Computing Sciences] 66
type UserFile = CsvProvider<"someFile.csv"> Generate types from some fjle containing (sample) data.
[Faculty of Science Information and Computing Sciences] 67
let userFileInstance = UserFile.Load("sameOrMaybeAnotherFile.csv") print userFileInstance.firstRow.name Create instance and access data. ‘Normal code’.
[Faculty of Science Information and Computing Sciences] 68
What about databases?
type DatabaseSource = DatabaseProvider<"www.mydatabase.com/types"> let databaseConnection = DatabaseSource.Connect("www.mydatabase.com") // ...perform queries on databaseConnection
[Faculty of Science Information and Computing Sciences] 69
Great… so?
▶ Type checking. ▶ Auto-completion. ▶ Connections/fjles etc. ▶ Extend types.
We could already do all these things.
[Faculty of Science Information and Computing Sciences] 70
But… it’s all in one place.
[Faculty of Science Information and Computing Sciences] 71
More: regular expressions.
type T = RegexTyped< @"(?<AreaCode>^\d{3})- (?<PhoneNumber>\d{3}-\d{4}$)"> let reg = T() let result = T.IsMatch("425-555-2345") Limitation: string has to be known at compile-time.
[Faculty of Science Information and Computing Sciences] 72
How do you actually write a type provider?
[<TypeProvider>] type CsvProvider(config: TypeProviderConfig) as this = //
[Faculty of Science Information and Computing Sciences] 73
- 1. Add static parameters to the type provider.
- 2. Call ProvidedTypeDefjnition to provide the base type.
- 3. Add methods such as Load and members such as Rows to
the base type.
- 4. Open the sample fjle.
- 5. Infer the type from each column and add these types.
[Faculty of Science Information and Computing Sciences] 74
Biggest limitation.
Static parameters can only be primitive types.
[Faculty of Science Information and Computing Sciences] 75