Concepts of programming languages - F# · F# Tim Zoet, Zino Onomiwo, Martijn Boom, Rik van Toor...

Post on 03-Oct-2020

1 views 0 download

transcript

[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.