Introduction to SML Basic Types, Tuples, Lists, Trees and Higher-Order Functions Michael R. Hansen mrh@imm.dtu.dk Informatics and Mathematical Modelling Technical University of Denmark c Michael R. Hansen, Spring 2005 p.1/59
Basic Types: Integers A data type comprises a set of values and a collection of operations c Michael R. Hansen, Spring 2005 p.2/59
Basic Types: Integers A data type comprises a set of values and a collection of operations Integers Type name : int Values : 27, 0, 1024 Operations: (A few selected) Operator Type Precedence Association int -> int Highest * div mod int * int -> int 7 Left + - int * int -> int 6 Left = <> < <= int * int -> bool 4 Left See also the library Int c Michael R. Hansen, Spring 2005 p.2/59
Reals Type name : real Values : 27.0, 0.0, 1024.71717, 23.4E 11 Operations: (A few selected) Operator Type Precedence Association abs real -> real Highest * / real*real -> real 7 Left + - real*real -> real 6 Left = <> < <= real*real -> bool 4 Left See also the libraries Real and Math c Michael R. Hansen, Spring 2005 p.3/59
Reals Type name : real Values : 27.0, 0.0, 1024.71717, 23.4E 11 Operations: (A few selected) Operator Type Precedence Association abs real -> real Highest * / real*real -> real 7 Left + - real*real -> real 6 Left = <> < <= real*real -> bool 4 Left See also the libraries Real and Math Some built-in operators are overloaded. *: Default is int real*real -> real int * int -> int c Michael R. Hansen, Spring 2005 p.3/59
Overloaded Operators and Type inference A squaring function on integers: Declaration Type fun square x = x * x int -> int Default c Michael R. Hansen, Spring 2005 p.4/59
Overloaded Operators and Type inference A squaring function on integers: Declaration Type fun square x = x * x int -> int Default A squaring function on reals: square: real -> real Declaration c Michael R. Hansen, Spring 2005 p.4/59
Overloaded Operators and Type inference A squaring function on integers: Declaration Type fun square x = x * x int -> int Default A squaring function on reals: square: Declaration fun square(x:real) = x * x real -> real Type the argument c Michael R. Hansen, Spring 2005 p.4/59
Overloaded Operators and Type inference A squaring function on integers: Declaration Type fun square x = x * x int -> int Default A squaring function on reals: square: real -> real Declaration fun square x:real = x * x Type the result c Michael R. Hansen, Spring 2005 p.4/59
Overloaded Operators and Type inference A squaring function on integers: Declaration Type fun square x = x * x int -> int Default A squaring function on reals: square: real -> real Declaration fun square x = x * x: real Type expression for the result c Michael R. Hansen, Spring 2005 p.4/59
Overloaded Operators and Type inference A squaring function on integers: Declaration Type fun square x = x * x int -> int Default A squaring function on reals: square: real -> real Declaration fun square x = x:real * x Type a variable c Michael R. Hansen, Spring 2005 p.4/59
Overloaded Operators and Type inference A squaring function on integers: Declaration Type fun square x = x * x int -> int Default A squaring function on reals: square: real -> real Declaration fun square x = x:real * x Type a variable Choose any mixture of these possibilities c Michael R. Hansen, Spring 2005 p.4/59
Characters Type name char Values #"a", #" ", #"\"" (escape sequence for ") Operator Type ord char -> int ascii code of character chr int -> char character for ascii code = < <=... char*char -> bool comparisons by ascii codes Examples - ord #"a"; > val it = 97 : int - ord #"A"; > val it = 65 : int - #"a" < #"A"; > val it = false : bool; - chr 88; > val it = #"X" : char c Michael R. Hansen, Spring 2005 p.5/59
Strings Type name string Values "abcd", " ", "", "123\"321" (escape sequence for ") Operator Type size string -> int length of string ˆ string*string -> string concatenation = < <=... string*string -> bool comparisons Int.toString int -> string conversions Examples - "auto" < "car"; > val it = true : bool - "abc"ˆ"de"; > val it = "abcde": string - size("abc"ˆ"def"); > val it = 6 : int - Int.toString(6+18); > val it = "24" : string c Michael R. Hansen, Spring 2005 p.6/59
Booleans Type name bool Values false, true Operator Type not bool -> bool negation not true = false not false = true Expressions e 1 andalso e 2 conjunction e 1 e 2 e 1 orelse e 2 disjunction e 1 e 2 are lazily evaluated, e.g. 1<2 orelse 5/0 = 1 true Precedence: andalse has higher than orelse c Michael R. Hansen, Spring 2005 p.7/59
Tuples An ordered collection of n values (v 1, v 2,..., v n ) is called an n-tuple Examples - (); > val it = () : unit - (3, false); > val it = (3, false) : int * bool - (1, 2, ("ab",true)); > val it = (1, 2, ("ab", true)) :? 0-tuple 2-tuples (pairs) 3-tuples (triples) Selection Operation: #i(v 1, v 2,..., v n ) = v i. #2(1,2,3) = 2 Equality defined componentwise - (1, 2.0, true) = (2-1, 2.0*1.0, 1<2); > val it = true : bool provided = is defined on components c Michael R. Hansen, Spring 2005 p.8/59
Tuple patterns Extract components of tuples - val ((x,_),(_,y,_)) = ((1,true),("a","b",false)); > val x = 1 : int val y = "b" : string Pattern matching yields bindings Restriction - val (x,x) = (1,1);! Toplevel input:! val (x,x) = (1,1);! ˆ! identifier is bound twice in a pattern c Michael R. Hansen, Spring 2005 p.9/59
Infix functions Directives: infix d f and infixr d f. d is the precedence of f Example: exclusive-or infix 0 xor (* or just infix xor -- lowest precedence *) fun false xor true = true true xor false = true _ xor _ = false type? - 1 < 2+3 xor 2.0 / 3.0 > 1.0; > val it = true : bool Infix status can be removed by nonfix xor - xor(1 < 2+3, 2.0 / 3.0 > 1.0); > val it = true : bool c Michael R. Hansen, Spring 2005 p.10/59
Let expressions let dec in e end Bindings obtained from dec are valid only in e Example: Solve ax 2 + bx + c = 0 type equation = real * real * real type solution = real * real exception Solve; (* declares an exception *) fun solve(a,b,c) = let val d = b*b-4.0*a*c in if d < 0.0 orelse a = 0.0 then raise Solve else (( b+math.sqrt d)/(2.0*a),( b-math.sqrt d)/(2.0*a)) end; The type of solve is equation -> solution d is declared once and used 3 times readability, efficiency c Michael R. Hansen, Spring 2005 p.11/59
Local declarations local dec 2 in dec 2 end Bindings obtained from dec 1 are valid only in dec 2 local fun disc(a,b,c) = b*b - 4.0*a*c in exception Solve; fun hastwosolutions(a,b,c) = disc(a,b,c)>0.0 andalso a<>0.0; fun solve(a,b,c) = let val d = disc(a,b,c) in if d < 0.0 orelse a = 0.0 then raise Solve else (( b+math.sqrt d)/(2.0*a),( b-math.sqrt d)/(2.0*a)) end end; c Michael R. Hansen, Spring 2005 p.12/59
Lists: Overview values and constructors recursions following the structure of lists useful built-in functions polymorphic types, values and functions c Michael R. Hansen, Spring 2005 p.13/59
Lists A list is a finite sequence of elements having the same type: [v 1,..., v n ] ([ ] is called the empty list) c Michael R. Hansen, Spring 2005 p.14/59
Lists A list is a finite sequence of elements having the same type: [v 1,..., v n ] ([ ] is called the empty list) - [2,3,6]; > val it = [2, 3, 6] : int list c Michael R. Hansen, Spring 2005 p.14/59
Lists A list is a finite sequence of elements having the same type: [v 1,..., v n ] ([ ] is called the empty list) - ["a", "ab", "abc", ""]; > val it = ["a", "ab", "abc", ""] : string list c Michael R. Hansen, Spring 2005 p.14/59
Lists A list is a finite sequence of elements having the same type: [v 1,..., v n ] ([ ] is called the empty list) - [Math.sin, Math.cos]; > val it = [fn, fn] : (real -> real) list c Michael R. Hansen, Spring 2005 p.14/59
Lists A list is a finite sequence of elements having the same type: [v 1,..., v n ] ([ ] is called the empty list) - [(1,true), (3,true)]; > val it = [(1, true),(3, true)]: (int*bool) list c Michael R. Hansen, Spring 2005 p.14/59
Lists A list is a finite sequence of elements having the same type: [v 1,..., v n ] ([ ] is called the empty list) - [[],[1],[1,2]]; > val it = [[], [1], [1, 2]] : int list list c Michael R. Hansen, Spring 2005 p.14/59
The type constructor: list If τ is a type, so is τ list Examples: int list (string * int) list ((int -> string) list ) list list has higher precedence than * and -> int * real list -> bool list means (int * (real list)) -> (bool list) c Michael R. Hansen, Spring 2005 p.15/59
Trees for lists A non-empty list [x 1, x 2,..., x n ], n 1, consists of a head x 1 and a tail [x 2,..., x n ] c Michael R. Hansen, Spring 2005 p.16/59
Trees for lists A non-empty list [x 1, x 2,..., x n ], n 1, consists of a head x 1 and a tail [x 2,..., x n ] :: 2 :: 3 :: 2 nil Graph for [2,3,2] :: 2 nil Graph for [2] c Michael R. Hansen, Spring 2005 p.16/59
List constructors: [], nil and :: Lists are generated as follows: the empty list is a list, designated [] or nil if x is an element and xs is a list, then so is x :: xs (type consistency) :: associate to the right, i.e. x 1 ::x 2 ::xs c Michael R. Hansen, Spring 2005 p.17/59
List constructors: [], nil and :: Lists are generated as follows: the empty list is a list, designated [] or nil if x is an element and xs is a list, then so is x :: xs (type consistency) :: associate to the right, i.e. x 1 ::x 2 ::xs means x 1 ::(x 2 ::xs) c Michael R. Hansen, Spring 2005 p.17/59
List constructors: [], nil and :: Lists are generated as follows: the empty list is a list, designated [] or nil if x is an element and xs is a list, then so is x :: xs (type consistency) :: associate to the right, i.e. x 1 ::x 2 ::xs means x 1 ::(x 2 ::xs) :: x 1 :: x 2 xs Graph for x 1 ::x 2 ::xs c Michael R. Hansen, Spring 2005 p.17/59
Recursion on lists a simple example n suml [x 1,x 2,...,x n ] = x i = x 1 + x 2 + + x n = x 1 + i=1 n i=2 x i Constructors are used in list patterns fun suml [] = 0 suml( x::xs) = x + suml xs > val suml = fn : int list -> int suml [1,2] 1 + suml [2] (x 1 and xs [2]) 1 + (2 + suml []) (x 2 and xs []) 1 + (2 + 0) (the pattern [] matches the value []) 1 + 2 3 Recursion follows the structure of lists c Michael R. Hansen, Spring 2005 p.18/59
Append The infix operator @ (called append ) joins two lists: Properties [x 1,x 2,...,x m ] @ [y 1,y 2,...,y n ] = [x 1,x 2,...,x m,y 1,y 2,...,y n ] [] @ ys = ys [x 1,x 2,...,x m ] @ ys = x 1 ::([x 2,...,x m ] @ ys) Declaration infixr 5 @ (* right associative fun [] @ ys = ys (x::xs) @ ys = x::(xs @ ys); c Michael R. Hansen, Spring 2005 p.19/59
Append: evaluation infixr 5 @ (* right associative *) fun [] @ ys = ys (x::xs) @ ys = x::(xs @ ys); Evaluation [1,2] @ [3,4] 1::([2] @ [3,4]) (x 1, xs [2], ys [3, 4]) 1::(2::([] @ [3,4])) (x 2, xs [ ], ys [3, 4]) 1::(2::[3,4]) (ys [3, 4]) 1::[2,3,4] [1,2,3,4] c Michael R. Hansen, Spring 2005 p.20/59
Append: polymorphic type > infixr 5 @ > val @ = fn : a list * a list -> a list a is a type variable The type of @ is polymorphic it has many forms a = int: Appending integer lists [1,2] @ [3,4]; val it = [1,2,3,4] : int list a = int list: Appending lists of integer list [[1],[2,3]] @ [[4]]; val it = [[1],[2,3],[4]] : int list list @ is a built-in function c Michael R. Hansen, Spring 2005 p.21/59
Reverse rev [x 1, x 2,..., x n ] = [x n,..., x 2, x 1 ] fun naive_rev [] = [] naive_rev(x::xs) = naive_rev xs @ [x]; val naive_rev = fn : a list -> a list naive_rev[1,2,3] naive_rev[2,3] @ [1] (naive_rev[3] @ [2]) @ [1] ((naive_rev[] @ [3]) @ [2]) @ [1] (([] @ [3]) @ [2]) @ [1] ([3] @ [2]) @ [1] (3::([] @ [2])) @ [1] [3,2,1] efficient version is built-in (see Ch. 17) c Michael R. Hansen, Spring 2005 p.22/59
Membership equality types Declaration infix member x member [y 1,y 2,...,y n ] = (x = y 1 ) (x = y 2 ) (x = y n ) = (x = y 1 ) (x member [y 2,...,y n ]) fun x member [] = false x member (y::ys) = x=y orelse x member ys; infix 0 member val member = fn : a * a list -> bool a is an equality type variable no functions (1,true) member [(2,true), (1,false)] false [1,2,3] member [[1], [], [1,2,3]]? c Michael R. Hansen, Spring 2005 p.23/59
Value polymorphism e is a value expression if no further evaluation is needed - (5,[]); (* val it = (5,[]); *) > val a it = (5, []) : int * a list - rev []; (* non-value expression *)! Warning: Value polymorphism:! Free type variable(s) at top level in value id. it A type is monomorphic is it contains no type variables, otherwise it is polymorphic SML resticts the use of polymorphic types as follows: see Ch. 18 all monomorphic expressions are OK all value expressions are OK at top-level, polymorphic non-value expressions are forbidden c Michael R. Hansen, Spring 2005 p.24/59
Examples remove(x, ys) : removes all occurrences of x in the list ys prefix(xs, ys) : the list xs is a prefix of the list ys (ex. 5.10) sum(p, xs) : the sum of all elements in xs satisfying the predicate p: int -> bool (ex. 5.15) From list of pairs to pair of lists: unzip [(x 1, y 1 ), (x 2, y 2 ),..., (x n, y n )] = ([x 1, x 2,..., x n ], [y 1 y 2,..., y n ]) Many functions on lists are predefined, e.g. @, rev, length, and also the SML basis library contains functions on lists, e.g. unzip. See for example List, ListPair c Michael R. Hansen, Spring 2005 p.25/59
Overview Disjoint Sets The datatype simple version case expressions c Michael R. Hansen, Spring 2005 p.26/59
Disjoint Sets: An Example A shape is either a circle, a square, or a triangle the union of three disjoint sets A datatype declaration for shapes: datatype shape = Circle of real Square of real Triangle of real*real*real; Answer from the SML system: > datatype shape > con Circle = fn : real -> shape > con Square = fn : real -> shape > con Triangle = fn : real * real * real -> shape c Michael R. Hansen, Spring 2005 p.27/59
Constructors of a datatype The tags Circle, Square and Triangle are constructors of values of type shape - Circle 2.0; > val it = Circle 2.0 : shape - Triangle(1.0, 2.0, 3.0); > val it = Triangle(1.0, 2.0, 3.0) : shape - Square 4.0; > val it = Square 4.0 : shape Equality on shapes is defined provided... - Triangle(1.0, 2.0, 3.0) = Square 2.0; > val it = false : bool c Michael R. Hansen, Spring 2005 p.28/59
Constructors in Patterns fun area(circle r) = Math.pi * r * r area(square a) = a * a area(triangle(a,b,c)) = let val d = (a + b + c)/2.0 in Math.sqrt(d*(d-a)*(d-b)*(d-c)) end; > val area = fn : shape -> real a constructor only matches itself area (Circle 1.2) (Math.pi * r * r, [r 1.2])... c Michael R. Hansen, Spring 2005 p.29/59
The case-expression Form: case exp of pat 1 => e 1 pat 2 => e 2... pat k => e k Example: fun area s = case s of (Circle r) => Math.pi * r * r (Square a) => a*a (Triangle(a,b,c)) => let val d = (a + b + c)/2.0 in Math.sqrt(d*(d-a)*(d-b)*(d-c)) end; c Michael R. Hansen, Spring 2005 p.30/59
Enumeration types the order type datatype order = LESS EQUAL GREATER; Predefined compare functions, e.g. LESS if x < y Int.compare(x, y) = EQUAL if x = y GREATER if x > y Example: fun countleg [] = (0,0,0) countleg(x::rest) = let val (y1,y2,y3) = countleg rest in case Int.compare(x,0) of LESS => (y1+1,y2,y3 ) EQUAL => (y1,y2+1,y3 ) GREATER => (y1,y2,y3+1) end; c Michael R. Hansen, Spring 2005 p.31/59
The option type datatype a option = NONE SOME of a; Example fun smallest [] = NONE smallest(x::xs) = case smallest xs of NONE => SOME x SOME y => if x< y then SOME x else SOME y; > val smallest = fn : int list -> int option - smallest [2, 3, 6]; > val it = SOME 3 : int option c Michael R. Hansen, Spring 2005 p.32/59
smallest continued The predefined function valof: exception Option; fun valof(some x) = x valof NONE = raise Option; > val a valof = fn : a option -> a - 3 + valof(smallest [1,2,9]); > val it = 4 : int c Michael R. Hansen, Spring 2005 p.33/59
Overview Finite Trees Algebraic Datatypes. Recursions following the structure of trees. c Michael R. Hansen, Spring 2005 p.34/59
Trees A finite tree is a value which may contain a subcomponent of the same type. Example: A binary search tree Br Br Br Br 7 Lf Br 21 Br Lf 2 Lf 9 Lf 13 Lf Lf 25 Lf Condition: for every node containing the value x: every value in the left subtree is smaller then x, and every value in the right subtree is greater than x. c Michael R. Hansen, Spring 2005 p.35/59
Binary Trees A recursive datatype is used to represent values with are trees. datatype tree = Lf Br of tree*int*tree; > datatype tree > con Lf = Lf : tree > con Br = fn : tree * int * tree -> tree c Michael R. Hansen, Spring 2005 p.36/59
Binary Trees A recursive datatype is used to represent values with are trees. datatype tree = Lf Br of tree*int*tree; > datatype tree > con Lf = Lf : tree > con Br = fn : tree * int * tree -> tree The two parts in the declaration are rules for generating trees: Lf is a tree if t 1, t 2 are trees, n is an integer, then Br(t 1, n, t 2 ) is a tree. c Michael R. Hansen, Spring 2005 p.36/59
Binary Trees A recursive datatype is used to represent values with are trees. datatype tree = Lf Br of tree*int*tree; > datatype tree > con Lf = Lf : tree > con Br = fn : tree * int * tree -> tree The two parts in the declaration are rules for generating trees: Lf is a tree if t 1, t 2 are trees, n is an integer, then Br(t 1, n, t 2 ) is a tree. The tree from the previous slide is denoted by: Br(Br(Br(Lf,2,Lf),7,Lf), 9, Br(Br(Lf,13,Lf),21,Br(Lf,25,Lf))) c Michael R. Hansen, Spring 2005 p.36/59
Binary search trees: Insertion Recursion on the structure of trees: Constructors Lf and Br are used in patterns fun insert(i, Lf) = Br(Lf,i,Lf) insert(i, tr as Br(t1,j,t2)) = case Int.compare(i,j) of EQUAL => tr LESS => Br(insert(i,t1),j,t2) GREATER => Br(t1,j,insert(i,t2)) The search tree condition is an invariant for insert Example: - val t1 = Br(Lf, 3, Br(Lf, 5, Lf)); - val t2 = insert(4, t1); > val t2 = Br(Lf, 3, Br(Br(Lf, 4, Lf), 5, Lf)) : tree c Michael R. Hansen, Spring 2005 p.37/59
Binary search trees: member and tolist fun member(i, Lf) = false member(i, Br(t1,j,t2)) = case Int.compare(i,j) of EQUAL => true LESS => member(i,t1) GREATER => member(i,t2) > val member = fn : int * tree -> bool In-order traversal fun tolist Lf = [] tolist(br(t1,j,t2)) = tolist t1 @ [j] @ tolist t2; > val tolist = fn : tree -> int list gives a sorted list - tolist(br(br(lf,1,lf), 3, Br(Br(Lf,4,Lf), 5, Lf))); > val it = [1, 3, 4, 5] : int list c Michael R. Hansen, Spring 2005 p.38/59
Deletions in search trees Delete minimal element in a search tree: tree -> int * tree fun delmin(br(lf,i,t2)) = (i,t2) delmin(br(t1,i,t2)) = let val (m,t1 ) = delmin t1 in (m, Br(t1,i,t2)) end Delete element in a search tree: tree * int -> tree fun delete(lf,_) = Lf delete(br(t1,i,t2),j) = case Int.compare(i,j) of LESS => Br(t1,i,delete(t2,j)) GREATER => Br(delete(t1,j),i,t2) EQUAL => (case (t1,t2) of (Lf,_) => t2 (_,Lf) => t1 _ => let val (m,t2 ) = delmin t2 in Br(t1,m,t2 ) end) c Michael R. Hansen, Spring 2005 p.39/59
Expression Trees infix 6 ++ --; infix 7 ** //; datatype fexpr = Const of real X ++ of fexpr * fexpr -- of fexpr * fexpr ** of fexpr * fexpr // of fexpr * fexpr > datatype fexpr con ** : fexpr * fexpr -> fexpr con ++ : fexpr * fexpr -> fexpr con -- : fexpr * fexpr -> fexpr con // : fexpr * fexpr -> fexpr con X : fexpr con Const : real -> fexpr c Michael R. Hansen, Spring 2005 p.40/59
Expressions: Computation of values comp : fexpr * real -> real fun comp(const r,_) = r comp(x,y) = y comp(fe1 ++ fe2,y) = comp(fe1,y) + comp(fe2,y) comp(fe1 -- fe2,y) = comp(fe1,y) - comp(fe2,y) comp(fe1 ** fe2,y) = comp(fe1,y) * comp(fe2,y) comp(fe1 // fe2,y) = comp(fe1,y) / comp(fe2,y) Example: comp(x ** (Const 2.0 ++ X), 4.0); > val it = 24.0 : real c Michael R. Hansen, Spring 2005 p.41/59
Overview Contents Higher-order functions Anonymous functions Higher-order list functions (in the library) map exists, all, filter foldl, foldr Many recursive declarations follows the same schema. Succinct declarations using higher-order functions. Parameterization of program modules c Michael R. Hansen, Spring 2005 p.42/59
Higher-order functions A function f : τ 1 τ 2 is a higher-order function, if a function type τ τ occurs in either τ 1 or τ 2 or both. Functions are first class citizens c Michael R. Hansen, Spring 2005 p.43/59
Higher-order functions A function f : τ 1 τ 2 is a higher-order function, if a function type τ τ occurs in either τ 1 or τ 2 or both. fun f x = let fun g y = x+y in g end; > val f = fn : int -> int -> int - f 2; > val it = fn : int -> int - it 3; > val it = 5 : int Functions are first class citizens c Michael R. Hansen, Spring 2005 p.43/59
Anonymous functions Expressions denoting functions can be written using fn expressions: fn pat 1 => e 1 pat 2 => e 2 pat n => e n Yields the value obtained by evaluation of the expression: let fun f x = case x of pat 1 => e 1 pat 2 => e 2 pat n => e n in f end Examples: fn n => 2 * n; fn 0 => false _ => true; fn r => Math.pi * r * r; c Michael R. Hansen, Spring 2005 p.44/59
Declarations having the same structure fun poslist [] = [] poslist (x::xs) = (x > 0)::posList xs; val poslist = fn : int list -> bool list poslist [4, 5, 6]; > val it = [true,false,true] : bool list Applies the function fn x => x > 0 to each element in a list fun addelems [] = [] addelems ((x,y)::zs) = (x + y)::addelems zs; > val addelems = fn : (int * int) list -> int list addelems [(1,2),(3,4)]; > val it = [3, 7] : int list Applies the sum function op+ to each pair of integers in a list c Michael R. Hansen, Spring 2005 p.45/59
The function: map Applies a function to each element in a list map f [v 1, v 2,..., v n ] = [f(v 1 ), f(v 2 ),..., f(v n )] Declaration Library function fun map f = fn [] => [] (x::xs) => f x :: map f xs; > val map = fn : ( a -> b) -> a list -> b list Succinct declarations can be achieved using map, e.g. val poslist = map (fn x => x > 0); > val poslist = fn : int list -> bool list val addelems = map op+ - val addelems = fn : (int * int) list -> int list c Michael R. Hansen, Spring 2005 p.46/59
Declaration of higher-order functions Commonly used form fun map f [] = [] map f (x::xs) = f x :: map f xs; > val map = fn : ( a -> b) -> a list -> b list General form fun f pat 11 pat 12... pat 1n = e 1 f pat 21 pat 22... pat 2n = e 2... f pat k1 pat k2... pat kn = e k c Michael R. Hansen, Spring 2005 p.47/59
Exercise Declare a function g [x 1,..., x n ] = [x 2 1 + 1,..., x 2 n + 1] Remember map f [v 1, v 2,..., v n ] = [f(v 1 ), f(v 2 ),..., f(v n )] c Michael R. Hansen, Spring 2005 p.48/59
Higher-order list functions: exists exists p xs = { true false if p(x) = true for some x in xs otherwise Declaration Library function fun exists p [] = false exists p (x::xs) = p x orelse exists p xs; > val exists = fn: ( a -> bool) -> a list -> bool Example exists (fn x => x>=2) [1,3,1,4]; > val it = true : bool c Michael R. Hansen, Spring 2005 p.49/59
Exercise Declare member function using exists. infix member; fun x member ys = exists????? ; > val member = fn : a * a list -> bool Remember exists p xs = { true false if p(x) = true for some x in xs otherwise c Michael R. Hansen, Spring 2005 p.50/59
Higher-order list functions: all { all p xs = true false if p(x) = true, for all elements x in xs otherwise Declaration Library function fun all p [] = true all p (x::xs) = p x andalso all p xs; > val all = fn: ( a -> bool) -> a list -> bool Example all (fn x => x>=2) [1,3,1,4]; > val it = false : bool c Michael R. Hansen, Spring 2005 p.51/59
Exercise Declare a function subset(xs, ys) which is true when every element in the lists xs is in ys, and false otherwise. Remember all p xs = { true false if p(x) = true, for all elements x in xs otherwise c Michael R. Hansen, Spring 2005 p.52/59
Higher-order list functions: filter filter p xs is the list of those elements x of xs where p(x) = true. Declaration Library function fun filter p [] = [] filter p (x::xs) = if p x then x :: filter p xs else filter p xs; > val filter = fn: ( a -> bool) -> a list -> a list Example filter Char.isAlpha [#"1", #"p", #"F", #"-"]; > val it = [#"p", #"F"] : char list where Char.isAlpha c is true iff c {#"A",..., #"Z"} {#"a",..., #"z"} c Michael R. Hansen, Spring 2005 p.53/59
Exercise Declare a function inter(xs, ys) which contains the common elements of the lists xs and ys i.e. their intersection. Remember filter p xs is the list of those elements x of xs where p(x) = true. c Michael R. Hansen, Spring 2005 p.54/59
Higher-order list functions: foldr (1) foldr accumulates a function f from a start value b over the elements of a list [x 1, x 2,..., x n ] (from right to left): foldr f b [x 1, x 2,..., x n 1, x n ] = f(x 1, f(x 2,..., f(x n 1, f(x n, b)) )) }{{} foldr f b [x 2,...,x n 1,x n ] Declaration Library function fun foldr f b [] = b foldr f b (x::xs) = f(x,foldr f b xs); > val foldr = fn : ( a * b -> b) -> b -> a list -> b Example: the lenght function fun length xs = foldr (fn (_,y) => y+1) 0 xs; > val length = fn : a list -> int length [4,5,6]; > val it = 3 : int c Michael R. Hansen, Spring 2005 p.55/59
Higher-order list functions: foldr (2) Accumulation of an infix operator. Evaluation is as follows foldr op b [x 1,x 2,...,x n ] x 1 (x 2 (x n b) ) Examples: Addition and Append fun sumr xs = foldr op+ 0 xs; > val sumr = fn : int list -> int sumr [1,2,3,4]; > val it = 10 : int fun append(xs,ys) = foldr op:: ys xs; > val append = fn : a list * a list -> a list append([1,2,3],[4,5]); > val it = [1,2,3,4,5] : int list c Michael R. Hansen, Spring 2005 p.56/59
Exercise: union of sets Let an insertion function be declared by fun insert(x, ys) = if x member ys then ys else x::ys Declare a union function on sets. Remember: foldr op b [x 1,x 2,...,x n ] x 1 (x 2 (x n b) ) c Michael R. Hansen, Spring 2005 p.57/59
Higher-order list functions: foldl (1) foldl accumulates a function f from a start value b over the elements of a list [x 1, x 2,..., x n ] (from left to right): b {}} { foldl f b [x 1,x 2,...,x n 1,x n ] = f(x n, f(x n 1,..., f(x 2, f(x 1, b)) )) }{{} foldl f b [x 2,...,x n 1,x n ] Declaration Library function fun foldl f b [] = b foldl f b (x::xs) = foldl f (f(x,b)) xs; > val foldl = fn : ( a * b -> b) -> b -> a list -> b c Michael R. Hansen, Spring 2005 p.58/59
Higher-order list functions: foldl (2) Accumulation of an infix operator. Evaluation is as follows foldl op b [x 1,x 2,...,x n ] (x n (x 2 (x 1 b)) ) Examples fun rev xs = foldl op:: [] xs; > val rev = fn : a list -> a list rev [1,2,3]; > val it = [3, 2, 1] : int list c Michael R. Hansen, Spring 2005 p.59/59