Programming language seminar 2011 The F# language Peter Sestoft Wednesday 2011-08-31 www.itu.dk 1 Course plan Four cycles, each containing a mini-project: F# Types and type inference Scala and Scala actors Programming language technology inside a highperformance spreadsheet implementation, more F# Final course report, individual, 10 pages Either continuation of a mini-project Or some other topic/language/... that you find interesting and want to explore Wednesdays (0900-1200) lectures or consultations, see homepage Homepage http://www.itu.dk/courses/splg/e2011/ www.itu.dk 2 1
Sources Hansen+Rischel: Functional programming with F# (DTU, draft 2011) PDF distributed only to this course; do not redistribute Sestoft: Programming Language Concepts for Software Developers (PLCSD), ITU August 2011 Complete PDF on course homepage Materials on Scala and Scala actors Sestoft: Spreadsheet technology (ITU, later 2011) Homepage http://www.itu.dk/courses/splg/e2011/ Schedule Reading materials Exercises Occasional example programs from lectures www.itu.dk 3 Why F# and Scala 2
F# Developed by Don Syme at Microsoft Research, Cambridge UK A functional language in the ML family With many additions and innovations Dimension types Object-oriented features Workflows (asynchronous computing) Runs on the.net platform (like C#, VB.NET) For Windows, Linux and MacOS Included in Visual Studio 2010 Or from http://msdn.microsoft.com/en-us/fsharp and use Mono 2.10 or.net redistributable www.itu.dk 5 F# values, declarations and types let res = 3+4;; let y = sqrt 2.0;; Expression let large = 10 < res;; Declaration y > 0.0 && 1.0/y > 7.0;; if 3 < 4 then 117 else 118;; let rektor = "Mads " + "Tofte";; Interactive system top-level fsi Strongly typed, types are inferred Immutability: let is binding not assignment 3
F# function definitions Function name Parameter let circlearea r = System.Math.PI * r * r;; let mul2 x = 2.0 * x;; > circlearea 10.0;; val it : float = 314.1592654 A function that finds the average of two floating-point numbers? www.itu.dk 7 F# recursive function definitions let rec fac (n : int) : int = if n=0 then 1 else n * fac(n-1);; Same in Java/C#/C/C++: int fac(int n) { if (n==0) return 1; else return n * fac(n-1); } www.itu.dk 8 4
F# type constraints let islarge x = 10 < x;; val islarge : int -> bool let islarge (x : float) : bool = 10.0 < x;; val islarge : float -> bool What if we give a wrong type constraint? www.itu.dk 9 F# pattern matching let rec fac n = match n with 0 -> 1 _ -> n * fac(n-1);; A pattern can be a variable a constant a wildcard (_) a constructor application x :: xr a list [] or [x] or x::y::xr a tuple (x, y) or (2, 29) or ([], x::xr) www.itu.dk 10 5
F# pairs and tuples let p = (2, 3);; let w = (2, true, 3.4, "blah");; let add (x, y) = x + y;; let noon = (12, 0);; let talk = (15, 15);; let earlier ((h1, m1), (h2, m2)) = h1<h2 (h1=h2 && m1<m2);; www.itu.dk 11 F# lists let x1 = [7; 9; 13];; let x2 = 7 :: 9 :: 13 :: [];; let equal = (x1 = x2);; What type would this list have: int list string list let ss = ["Dear"; title; name; "you have "];; let junkmail2 = String.concat " " ss;; let directory = [("IT dept", 5012); ("Kasper", 5170)];; www.itu.dk 12 6
List append (@) let x1 = [7; 9; 13];; let x3 = [47; 11];; let x1x3 = x1 @ x3;; Result is [7; 9; 13; 47; 11] x1 7 9 13 x3 47 11 x1x3 7 9 13 F# data (lists, pairs, ) are immutable This makes list sharing unobservable www.itu.dk 13 F# defining functions on lists let rec sum xs = match xs with [] -> 0 x::xr -> x + sum xr;; How compute the length of a list? How compute the average of a list? www.itu.dk 14 7
F# record types and records type phonerec = { name : string; phone : int };; let x = { name = "Kasper"; phone = 5170 };; x.name;; x.phone;; A record type for course information: title, teacher, semester? www.itu.dk 15 F# exceptions: raise and catch exception IllegalHour;; let mins h = if h < 0 h > 23 then raise IllegalHour else h * 60;; try (mins 25) with IllegalHour -> -1;; www.itu.dk 16 8
failwith raises the Failure exception let mins h = if h < 0 h > 23 then failwith "Illegal hour" else h * 60;; let mins h = if h < 0 h > 23 then failwithf "Illegal hour, h=%d" h else h * 60;; mins 25;; [...] FailureException: Illegal hour, h=25 Formatted failwith Like C printf www.itu.dk 17 F# algebraic datatypes Algebraic datatype, discriminated union A person is either a teacher or a student: type person = Student of string Teacher of string * int;; let people = [Student "Niels"; Teacher("Peter", 5083)];; let getphone person = match person with Teacher(name, phone) -> phone Student name -> failwith "no phone";; A type to represent weekdays? How would you do person/student/teacher in Java/C#? www.itu.dk 18 9
F# curried functions let addp (x, y) = x + y;; let res1 = addp(17, 25);; Type? let addc x y = x + y;; let res2 = addc 17 25;; Type? Function application is left associative: addc x y means (addc x) y The function type arrow is right associative: int -> int -> int means int -> (int -> int) What would (int -> int) -> int mean? www.itu.dk 19 Anonymous functions in F# A higher-order function takes another function as argument let rec map f xs = match xs with [] -> [] x::xr -> f x :: map f xr ( a-> b) -> ( a list -> b list) let mul2 x = 2.0 * x;; map mul2 [4.0; 5.0; 89.0];; [8.0; 10.0; 178.0] Anonymous functions map (fun x -> 2.0 * x) [4.0; 5.0; 89.0] [false; false; true] map (fun x -> x > 10.0) [4.0; 5.0; 89.0] www.itu.dk 20 10
Higher-order functions in C# C# delegate (function) types delegate R Func<R>() delegate R Func<A1,R>(A1 x1) delegate R Func<A1,A2,R>(A1 x1, A2 x2) unit -> int bool -> int int * bool -> string F# Func<int> Func<bool,int> Func<int,bool,string> C# 3.0 Anonymous function/method expressions fun (x:int) -> x>10 fun x -> x>10 fun x -> x*x F# (int x) => x>10 x => x>10 x => x*x C# 3.0 21 F# polymorphic functions let rec len xs = match xs with [] -> 0 x::xr -> 1 + len xr;; val len : 'a list -> int len [7; 9; 13] len [true; true; false; true] len ["foo"; "bar"] len [("Peter", 47)] The function doesn t look at the list elements so the function is polymorphic and works in any type of list Same as a generic method in Java or C# static int Count<T>(IEnumerable<T> xs) {... } www.itu.dk 22 11
F# polymorphic types type 'a tree = Lf Br of 'a * 'a tree * 'a tree Br(42, Lf, Lf) Br("quoi?", Lf, Lf) Br(("Peter", 47), Lf, Lf) The datatype has same structure regardless of node value type What type instances here? Same as a generic type in Java or C#: class ArrayList<T> {... } interface IEnumerable<T> {... } struct Pair<T,U> {... } delegate R Func<A,R>(A x); www.itu.dk 23 Polymorphic functions on polymorphic types let rec preorder1 t = match t with Lf -> [] Br(v, t1, t2) -> v :: preorder1 t1 @ preorder1 t2 Return the tree s node values in pre-order first root, then left subtree, then right subtree Works on any type of tree What is the type of this function? www.itu.dk 24 12
Accumulating parameters The append (@) operation may be slow A faster version of preorder, no append! let rec preo t acc = Accumulating match t with parameter Lf -> acc Br(v, t1, t2) -> v :: preo t1 (preo t2 acc);; let preorder2 t = preo t [];; This works because preo t acc = preorder1 t @ acc So preorder2 t = preo t [] = preorder1 t www.itu.dk O(n) versus O(n 2 ) Can be 1000 x faster Try #time;; in F# Uniform iteration over a list let rec sum xs = match xs with [] -> 0 x::xr -> x + sum xr let rec prod xs = match xs with [] -> 1 x::xr -> x * prod xr Generalizing 0/1 to e, and +/* to f: let rec foldr f xs e = match xs with [] -> e x::xr -> f x (foldr f xr e) int list -> int The foldr function replaces :: by f, and [] by e: foldr (x 1 ::x 2 :: ::x n ::[]) e = x 1 (x 2 (... (x n e) )) www.itu.dk ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b List.foldBack in F# 13
Many functions definable using foldr len xs = foldr (fun _ res -> 1+res) xs 0 sum xs = foldr (fun x res -> x+res) xs 0 prod xs = foldr (fun x res -> x*res) xs 1 map g xs = foldr (fun x res -> g x :: res) xs [] listconcat xss = foldr (fun xs res -> xs @ res) xss [] strconcat ss = foldr (fun s res -> s ^ res) ss " filter p xs = list of those x in xs for which p x is true forall p xs = p x is true for all x in xs exists p xs = p x is true for some x in xs www.itu.dk 27 Composing functions, pipe Given list xs, throw away small numbers, square the remaining numbers, and compute their sum: sum (map (fun x -> x*x) (filter (fun x -> x>10) xs)) Somewhat difficult to read: inside-out Idea: Define infix higher-order function > x > f = f x Now the list operations combine naturally: xs > filter (fun x -> x>10) > map (fun x -> x*x) > sum www.itu.dk 28 14
F# mutable references A reference is a cell that can be updated let r = ref 177!r (r :=!r+1;!r) Create int reference Dereference!r Assign to reference Useful for generation of new names etc: let nextlab = ref -1;; let newlabel () = (nextlab := 1 +!nextlab; "L" + string (!nextlab));; newlabel();; newlabel();; newlabel();; www.itu.dk Reading and exercises Install F# and experiment with it Either Visual Studio 2010 (a monster, available via your MSDNAA account) Or using Mono from www.mono-project.com Read Hansen & Rischel Chapters 1 to 5 There are exercises in Hansen & Rischel Do them as needed Or do the first steps of miniproject 1 www.itu.dk 30 15