200 likes | 420 Views
Haskell. Chapter 3, Part II. Topics. Guards Where Let Case (not emphasized). Guards. Guarded Command Language. Proposed by Dijkstra Statement of the form G -> S The guard is a proposition, must be true for statement to execute
E N D
Haskell Chapter 3, Part II
Topics • Guards • Where • Let • Case (not emphasized)
Guarded Command Language • Proposed by Dijkstra • Statement of the form G -> S • The guard is a proposition, must be true for statement to execute • Purpose: to support a new programming methodology that supported verification (correctness) during development • Basic Idea: if the order of evaluation is not important, the program should not specify one. All guards are evaluated, if more than one are true, choose one non-deterministically. • But in Haskell, they are evaluated top-down… more like an if-else from: http://en.wikipedia.org/wiki/Guarded_Command_Language
Haskell Guards bmiTell :: Double -> String bmiTellbmi | bmi <= 18.5 = "You're underweight, you emo, you!" | bmi <= 25.0 = "You're supposedy normal. Pffft. " | bmi <= 30.0 = "You're fat! Lose some weight." | otherwise = "You're a whale, congratulations!“ • At least one must evaluate to true, else error.
More examples • Guards can take two parameters max' :: (Ord a) => a -> a -> a max' a b | a <= b = b | otherwise = a myCompare :: (Ord a) => a-> a-> Ordering a `myCompare` b | a == b = EQ | a <= b = LT | otherwise = GT
where • purpose: avoid calculating same value multiple times • scope: only within function • defined at end of function, visible to all guards bmiTell :: Double -> Double -> String bmiTell weight height | bmi <= 18.5 = "You're underweight, you emo, you!" | bmi <= 25.0 = "You're supposedy normal. Pffft. " | bmi <= 30.0 = "You're fat! Lose some weight." | otherwise = "You're a whale, congratulations!" where bmi = (weight / height ^2) * 703
or even more “where” clauses • Names must line up! bmiTell' :: Double -> Double -> String bmiTell' weight height | bmi <= skinny = "You're underweight, you emo, you!" | bmi <= normal = "You're supposedy normal. Pffft. " | bmi <= fat = "You're fat! Lose some weight." | otherwise = "You're a whale, congratulations!" where bmi = (weight / height ^2) * 703 skinny = 18.5 normal = 25.0 fat = 30.0
limits to where • where bindings are not shared across different function bodies. So this does not work! greet :: String -> String greet "Juan" = niceGreeting ++ "Juan" greet "Fernando" = niceGreeting ++ "Fernando" greet name = badGreeting ++ name where niceGreeting = "Hello, so nice to see you, " badGreeting = "Oh, it you..."
Pattern matching with where initials :: String -> String -> String initials firstnamelastname = [f] ++ ". " ++ [l] ++ "." where (f:_) = firstname (l:_) = lastname
functions in where clause calcBmis :: [(Double, Double)] -> [Double] calcBmisxs = [bmi w h | (w, h) <- xs] where bmi weight height = (weight / height ^2) * 703
let • lets are expressions • allow you to bind variables • very local (don’t span guards) • can be used in pattern matching cylinder :: Double -> Double -> Double cylinder r h = let sideArea = 2 * pi * r * h topArea = pi * r ^ 2 in sideArea + 2 * topArea
more let • Introduce function in a local scope threeSquares = let square x = x * x in (square 5, square 3, square 2) • Bind to value aFormula = 4 * (let a = 9 in a + 1) + 2 • Pattern match to access list/tuple components threeTimesHundred = (let (a,b,c) = (1,2,3) in a+b+c) *100 • Use in list comprehensions calcBmis' :: [(Double, Double)] -> [Double] calcBmis' xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2]
let in GHCi • let binds names that can be used throughout GHCi session
let vs. where • where • is part of a syntactic construct • can be used to share bindings across parts of a function that are not syntactically expressions • let is an expression • expressions have values • let can be used almost anywhere in code … anywhere an expression can occur • but the scope of a let is only the expression which it encloses. • let y = a*b f x = (x+y)/yin f c + f d
case expression describeList :: [a] -> String describeListls = "The list is " ++ case ls of [] -> "empty" [a] -> "singleton" xs -> " longer"
play and share • cookTemp takes a string and returns a cook temperature (“Slow” = 350, “Medium” = 400, “Get ‘Er Done” = 450, otherwise 250) • cookTemp2 takes an integer and returns a string. Do the reverse of the above, use a where clause. Use inequalities. • greet takes a list in the form [“Cyndi”,”Ann”,”Rader”] and displays “Hello Cyndi Rader”. Use a where clause. Do it again with a let clause. • myInfo. Takes a nested list such as: [["Cyndi", "Rader"], ["Golden", "CO"]] or [["Cyndi", "Rader"]]. If the list contains both name and location (i.e., length 2), print “firstname lives in city” otherwise print “firstname lives somewhere”. Use a where clause for firstname and city • sumUsage takes a list of numbers that represent KB (e.g., from a directory) and creates the sum in MB (use a let function to do the conversion). • boo takes a list. If the list has four elements, add the first and third and multiply by 100. If the list has three elements, add the first and second and multiply by 100. (why? just for pattern matching practice)