Lecture 11: Guards (Haskell), Exceptions (SML) 1. Guards in Haskell pattern matching [RWH p68.] signum :: Int -> Int signum n = if n < 0 then -1 else if n == 0 then 0 else 1 signum n | n < 0 = -1 | n == 0 = 0 | otherwise = 1 ----------- maxThree :: Int -> Int -> Int -> Int maxThree x y z | x >= y && x >= z = x | y >= z = y | otherwise = z ------------ fact n = if n == 0 then 1 else n * fact (n-1) fact1 n | n == 0 = 1 | otherwise = n * fact1 (n-1) ----------- -- testing whether two lists have same first element eqhead :: [Int] -> [Int] -> Bool {- following won't work because nonlinear patterns not allowed eqhead (x:xs) (x:ys) = True -- nonlinear pattern (2 x's) eqhead _ _ = False -} eqhead (x:xs) (y:ys) | x == y = True | otherwise = False ========================================================== 2. Exceptions in SML [See Paulson, p. 134-141.] * type exn an "open" datatype where new data constructors can be added at any time exn data constructors are called exception constructors Some standard exceptions exception Match exception Empty exception Subscript exception Fail of string * Raising Expression Exceptions are used to signal exceptions or errors, or to escape from within a computation. fun hd [] = raise Empty | hd (x::xs) = x fun nth (n, nil) = raise Subscript | nth (0, x::xs) = x | nth (n, x::xs) = if n < 0 then raise Subscript else nth(n-1, xs) * Exceptions are handled by handle expressions fun default_nth k (n,l) = List.nth(n,l) handle Subscript => k * Example: association lists type 'a alist = (string * 'a) list exception Unbound fun bind (s, v, alist) = (s,v) :: alist fun lookup (s, nil) = raise Unbound | lookup (s, (s',v)::alist) = if s = s' then v else lookup(s,alist) * Example: 8 Queens Use of exceptions for "backtracking". val columns = [1,2,3,4,5,6,7,8]; fun safe (pos as (x,y), (x1,y1)::rest) = x <> x1 andalso (* not same column *) y <> y1 andalso (* not same row *) y-x <> y1-x1 andalso (* not same / diagonal *) y+x <> y1+x1 andalso (* not same \ diagonal *) safe (pos, rest) | safe (pos, nil) = true; exception Conflict; fun queens(posl, x, ys) = if x > 8 then posl else case ys of y::ys' => if safe((x,y), posl) then queens(posl@[(x,y)], x+1, columns) handle Conflict => queens(posl,x,ys') else queens(posl,x,ys') | [] => raise Conflict; val soln = queens([],1,columns); ----------------------------------------------------------------------