Concepts of programming languages - F# · F# Tim Zoet, Zino Onomiwo, Martijn Boom, Rik van Toor...
Transcript of Concepts of programming languages - F# · F# Tim Zoet, Zino Onomiwo, Martijn Boom, Rik van Toor...
[Faculty of ScienceInformation and Computing
Sciences]1
Concepts of programming languagesF#
Tim Zoet, Zino Onomiwo, Martijn Boom, Rik van Toor
[Faculty of ScienceInformation and Computing
Sciences]2
Background
▶ Don Syme▶ Microsoft Research▶ Recent development by the F# Software Foundation▶ Microsoft develops the Visual F# tools
[Faculty of ScienceInformation and Computing
Sciences]3
What is F#
▶ A first-class member of the .NET Framework.▶ Strongly related to ML and OCaml.▶ A hybrid language▶ Integration within Visual Studio
[Faculty of ScienceInformation and Computing
Sciences]4
Programming in F#
Hello World
let a_string = "World"printfn "Hello %s" a_string
[Faculty of ScienceInformation and Computing
Sciences]5
Types and variables
type name = stringlet author: name = "infinite monkey"
What features regarding types are supported in F#?
[Faculty of ScienceInformation and Computing
Sciences]6
Tuples, structures and more.
Tuples:
type tuple = int * stringlet tuple = (1, “hi!”) // Comma separated
Records
type Person = {Name:string; Age:int; Status:string} // named fields, semicolon separatedlet celebrity= {Name=”Gordon”, Age=49, Status=”single”}
[Faculty of ScienceInformation and Computing
Sciences]7
Tuples, structures and more.
Union
type Person =| CatPerson of string| DogPerson of string
let martijn = DogPerson “Martijn”
[Faculty of ScienceInformation and Computing
Sciences]8
Tuples, structures and more.
Recursive structures and unions:
type 'a union = A 'a | B 'atype 'a tree =
|EmptyTree| Node of 'a * 'a tree * 'a tree
[Faculty of ScienceInformation and Computing
Sciences]9
Tuples, structures and more.
Structures:
type Cat = structval Name: name;val Fur: colorval Env: environmentnew (n, f, e)
= {Name = n; Fur = f; Env = e}end
let cat: Cat = new Cat("Ottoman", RED, BLOCKCHAIN)
[Faculty of ScienceInformation 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 errorlet arr3 = [|for i in 1 .. 100 -> i * (i+1)|]printfn “%d” arr.[0] // prints 2printfn “%A” array // print [1; 2; 3; 4; 5]
[Faculty of ScienceInformation and Computing
Sciences]11
Lists and arrays
Listssingly 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 ScienceInformation and Computing
Sciences]12
Functions
let add x y = x + ylet sumOfSquares n =[1..n] |> List.map square |> List.sumsumOfSquares 100let adderGenerator = fun x -> (fun y -> x + y)
[Faculty of ScienceInformation and Computing
Sciences]13
Classes
type Exam(student, subject, grade) =member this.Student = studentmember this.Subject = subjectmember this.Grade = grade// public member
let stressLevel = 100 //private member
new Exam(“Socrates”, “Philosophy for dummies”, 10)
[Faculty of ScienceInformation and Computing
Sciences]14
Pattern matching
match x with| case1 -> …| case2 -> …| _ -> …
[Faculty of ScienceInformation 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 ScienceInformation 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 ScienceInformation and Computing
Sciences]17
Async
Ruin code in parallel
let motivationLevel (lvl, target) = async {printfn "Motivating %s till %i \%" target lvldo! Async.Sleep percentageprintfn "%s is %i \% motivated" target lvl}[(101, “Tim”), (65, “Rik”)]|> List.map motivationLevel|> Async.Parallel|> Async.RunSynchronously
[Faculty of ScienceInformation and Computing
Sciences]18
[<Measure>] type cm[<Measure>] type meter
let cmPerMeter = 10<cm/meter>let distanceToHomeCm = 100<cm>let distanceToHomeM = distanceToHomeCm * cmPerMeterlet otherConvert v: float<_> =match v with| :? float<cm> -> v * cmPerMeter| :? float<meter> -> v<meter>
[Faculty of ScienceInformation 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 ScienceInformation and Computing
Sciences]20
Relation to other languages
[Faculty of ScienceInformation 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 ScienceInformation 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 ScienceInformation 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 ScienceInformation and Computing
Sciences]24
Domain-driven design
type StreetAddress = {Line1:string; Line2:string;Line3:string }
type ZipCode = ZipCode of stringtype StateAbbrev = StateAbbrev of stringtype ZipAndState = {State:StateAbbrev; Zip:ZipCode }type USAddress = {Street:StreetAddress;
Region:ZipAndState}type UKPostCode = PostCode of stringtype UKAddress = {Street:StreetAddress;
Region:UKPostCode}
[Faculty of ScienceInformation and Computing
Sciences]25
Domain-driven design
type InternationalAddress = {Street:StreetAddress; Region:string;
CountryName:string}type Address = USAddress
| UKAddress| InternationalAddress
[Faculty of ScienceInformation and Computing
Sciences]26
Interoperability with C#
namespace interoperability.fsharp
type Beverage (brand:string, volume:int) =member this.Brand = brandmember this.Volume = volume
[Faculty of ScienceInformation and Computing
Sciences]27
using interoperability.fsharp;
namespace interoperability.csharp{class Program{
static void Main(string[] args){
//from record to classBeverage coke = new Beverage("Coca Cola", 330);Console.WriteLine(coke.name + “ “ + coke.Volume);
}}}
[Faculty of ScienceInformation and Computing
Sciences]28
using interoperability.fsharp;
namespace interoperability.csharp{class Program{
static void Main(string[] args){
//from record to classBeverage coke = new Beverage("Coca Cola", 330);Console.WriteLine(coke.name + “ “ + coke.Volume);
}}}
▶ output = “Coca Cola 330”
[Faculty of ScienceInformation and Computing
Sciences]29
namespace interoperability.fsharp
type Beverage (brand:string, volume:int) =member this.Brand = brandmember this.Volume = volume
module BeverageTasks =let drink (x:Beverage) = Beverage(x.Brand, 0)
[Faculty of ScienceInformation and Computing
Sciences]30
using interoperability.fsharp;
namespace interoperability.csharp{class Program{
static void Main(string[] args){
//from record to classBeverage coke = new Beverage("Coca Cola", 330);//from module to static classcoke = BeverageTasks.drink(coke)Console.WriteLine(coke.name + “ “ + coke.Volume);
}}}
[Faculty of ScienceInformation and Computing
Sciences]31
using interoperability.fsharp;
namespace interoperability.csharp{class Program{
static void Main(string[] args){
//from record to classBeverage coke = new Beverage("Coca Cola", 330);//from module to static classcoke = BeverageTasks.drink(coke);Console.WriteLine(coke.name + “ “ + coke.Volume);
}}}
output = “Coca Cola 0”
[Faculty of ScienceInformation and Computing
Sciences]32
namespace interoperability.fsharp
type Beverage (brand:string, volume:int) =member this.Brand = brandmember 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 ScienceInformation and Computing
Sciences]33
using interoperability.fsharp;
namespace interoperability.csharp{class Program{
static void Main(string[] args){
//from record to classBeverage coke = new Beverage("Coca Cola", 330);Console.WriteLine(BeverageTasks.message);BeverageTasks.message = "Not anymore!";Console.WriteLine(BeverageTasks.message);
}}}
[Faculty of ScienceInformation and Computing
Sciences]34
using interoperability.fsharp;
namespace interoperability.csharp{class Program{
static void Main(string[] args){
//from record to classBeverage 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 ScienceInformation and Computing
Sciences]35
type Taste =| Sweet = 'a'| Sour = 'b'| Bitter = 'c'| Salty = 'd'
Taste cokeTaste = Taste.Sweet;
[Faculty of ScienceInformation 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 ScienceInformation and Computing
Sciences]37
Relation to Haskell
▶ Both are functional languages▶ Both have cool logos
▶ Similar way of thinking while coding
[Faculty of ScienceInformation and Computing
Sciences]38
Relation to Haskell
F#
▶ Functional first
Haskell
▶ Purely functional
[Faculty of ScienceInformation and Computing
Sciences]39
Polymorphism
F#
▶ Does not really exist
Haskell
▶ Exists
[Faculty of ScienceInformation and Computing
Sciences]40
Polymorphism
Haskell (in GHCi):
> let square x = x * x> square 24> square 2.04.0
[Faculty of ScienceInformation 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 tohave type int
Caused by Type Inference.
[Faculty of ScienceInformation 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 ScienceInformation and Computing
Sciences]43
Polymorphism - More difficult
In Haskell:
class Showable a whereshw :: a -> String
data A = A Stringdata B = B Int
instance Showable A whereshw (A s) = s
instance Showable B whereshw (B i) = show i
[Faculty of ScienceInformation and Computing
Sciences]44
Polymorphism - More difficult
In F#:
type A = { thing: int }with static member show a = sprintf "%A" atype 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 ScienceInformation and Computing
Sciences]45
Polymorphism - More difficult
An alternative in F#:
type A = { thing: int }type B = { label: string }
type ThingThatShows =static member show(x:A) = sprintf "%A" xstatic member show(x:B) = sprintf "%A" x
This is called static member overloading
[Faculty of ScienceInformation 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 = somethingg
[Faculty of ScienceInformation 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 ScienceInformation 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 ScienceInformation 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 ofparentheses.
The same operator but inverted exists as well:
x y |> z is equal to z (x y).
[Faculty of ScienceInformation and Computing
Sciences]50
Evaluation
Haskell uses lazy evaluation.
F# uses eager evaluation by default, unless explicitly specifiedotherwise.
Example:
let always5 x = 5
[Faculty of ScienceInformation and Computing
Sciences]51
Evaluation
Haskell:
-- Will just return 5always5 $ map sqrt [1.0..1000000000.0]
F#:
//Will take a long timealways5 <| List.map sqrt [1.0..1000000000.0]
//Will just return 5always5 <| lazy(List.map sqrt [1.0..1000000000.0])
[Faculty of ScienceInformation and Computing
Sciences]52
Syntax
F#:
▶ A little more verbose than Haskell▶ More keywords than Haskell
Haskell:
▶ Amazing▶ The best
[Faculty of ScienceInformation 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 ScienceInformation and Computing
Sciences]54
Syntax - examples
F#
let rec sum list =match list with| head :: tail -> head + sum tail| [] -> 0
Haskell
sum [] = 0sum (head:tail) = head + sum tail
▶ Explicit rec
[Faculty of ScienceInformation and Computing
Sciences]55
Type providers
‘Information-rich programming’
[Faculty of ScienceInformation and Computing
Sciences]56
Making programming as easy as possible.
[Faculty of ScienceInformation and Computing
Sciences]57
Coincidentally the subject of our research project.
[Faculty of ScienceInformation and Computing
Sciences]58
▶ Generate types and add them to your project based onsome source containing type definitions.
▶ Type checking.▶ Auto-completion.▶ Integrated connection handling.
[Faculty of ScienceInformation and Computing
Sciences]59
Improvement on:
▶ Manual implementation▶ Code generation▶ (Runtime generation)
[Faculty of ScienceInformation and Computing
Sciences]60
Manual implementation
▶ Write F# type for every type in your information space.
[Faculty of ScienceInformation and Computing
Sciences]61
Manual implementation
▶ Updates of information space? Manual work…▶ Not doable in real world applications with thousands of
types.
[Faculty of ScienceInformation and Computing
Sciences]62
Code generation
▶ Generate F# types from e.g. a file containing typedefinitions.
[Faculty of ScienceInformation and Computing
Sciences]63
Code generation
▶ Rerun when information space changes.
[Faculty of ScienceInformation and Computing
Sciences]64
Example CSV
name age lengthAlice 42 1.69Bob 24 1.78Eve 32 1.75… … …
[Faculty of ScienceInformation and Computing
Sciences]65
type UserFile = CsvProvider<"someFile.csv">let userFileInstance =
UserFile.Load("sameOrMaybeAnotherFile.csv")print userFileInstance.firstRow.name
[Faculty of ScienceInformation and Computing
Sciences]66
type UserFile = CsvProvider<"someFile.csv">
Generate types from some file containing (sample) data.
[Faculty of ScienceInformation and Computing
Sciences]67
let userFileInstance =UserFile.Load("sameOrMaybeAnotherFile.csv")
print userFileInstance.firstRow.name
Create instance and access data. ‘Normal code’.
[Faculty of ScienceInformation 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 ScienceInformation and Computing
Sciences]69
Great… so?
▶ Type checking.▶ Auto-completion.▶ Connections/files etc.▶ Extend types.
We could already do all these things.
[Faculty of ScienceInformation and Computing
Sciences]70
But… it’s all in one place.
[Faculty of ScienceInformation 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 ScienceInformation and Computing
Sciences]72
How do you actually write a type provider?
[<TypeProvider>]type CsvProvider(config: TypeProviderConfig) as this =//
[Faculty of ScienceInformation and Computing
Sciences]73
1. Add static parameters to the type provider.2. Call ProvidedTypeDefinition to provide the base type.3. Add methods such as Load and members such as Rows to
the base type.4. Open the sample file.5. Infer the type from each column and add these types.
[Faculty of ScienceInformation and Computing
Sciences]74
Biggest limitation.
Static parameters can only be primitive types.
[Faculty of ScienceInformation and Computing
Sciences]75
Thank you for your attention
Please feel free to ask any questions.