This is an advanced topic to the post haskell - syntax in functions , where we wil dicuss the Guards in functions.
Whereas patterns are a way of making sure a value conforms to some form and deconstructing it, guards are a way of testing whether some property of a value (or several of them) are true or false. That sounds a lot like an if statement and it's very similar. The thing is that guards are a lot more readable when you have several conditions and they play really nicely with patterns.
the example of the pattern matching is as follow.
bmiTell :: (RealFloat a) => a -> String bmiTell bmi | bmi <= 18.5 = "You're underweight, you emo, you!" | bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!" | bmi <= 30.0 = "You're fat! Lose some weight, fatty!" | otherwise = "You're a whale, congratulations!"
the following will be discussed!
- the guard construct
- the where binding in the guard construct
- the otherwise keyword
the following code section will demonstrate how we can use the guard constructs.
-- guard -- Whereas patterns are a way of making sure a value conforms to some form and deconstructing it, guards are a way of testing whether some property of a value (or several of them) are true or false. -- Guard case -- Guards returns true or false -- it is a boolean expression bmiTell :: (RealFloat a ) => a -> String bmiTell bmi | bmi <= 18.5 = "You're underweight, you emo, you!" | bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!" | bmi <= 30.0 = "You're fat! Lose some weight, fatty!" | otherwise = "You're a whale, congratulations!" bmiTell' :: (RealFloat a) => a -> a -> String bmiTell' weight height | weight / height ^ 2 <= 18.5 = "You're underweight, you emo, you!" | weight / height ^ 2 <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!" | weight / height ^ 2 <= 30.0 = "You're fat! Lose some weight, fatty!" | otherwise = "You're a whale, congratulations!" max' :: (Ord a) => a -> a -> a max' a b | a > b = a | otherwise = b -- can write in one line -- max' :: (Ord a) => a -> a -> a -- max' a b | a > b = a | otherwise = b -- how the compare function are implemented myCompare :: (Ord a) => a -> a -> Ordering a `myCompare` b | a > b = GT | a == b = EQ | otherwise = LT -- 3 `myCompare` 2 -- the "where" clause in guard -- let's rewrite the bmiTell function bmiTell'' :: (RealFloat a) => a -> a -> String bmiTell'' weight height | bmi <= 18.5 = "You're underweight, you emo, you!" | bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!" | bmi <= 30.0 = "You're fat! Lose some weight, fatty!" | otherwise = "You're a whale, congratulations!" where bmi = weight / height ^ 2 -- We put the keyword where after the guards (usually it's best to indent it as much as the pipes are indented) and then we define several names or functions. -- These names are visible across the guards and give us the advantage of not having to repeat ourselves. -- the names are only visible to that function -- bmiTell3 :: (RealFloat a) => a -> a -> String bmiTell3 weight height | bmi <= skinny = "You're underweight, you emo, you!" | bmi <= normal = "You're supposedly normal. Pffft, I bet you're ugly!" | bmi <= fat = "You're fat! Lose some weight, fatty!" | otherwise = "You're a whale, congratulations!" where bmi = weight / height ^ 2 skinny = 18.5 normal = 25.0 fat = 30.0 -- where binding in "pattern matching!" initials :: String -> String -> String initials firstname lastname = [f] ++ ". " ++ [l] ++ "." where (f:_) = firstname (l:_) = lastname -- initials "joe" "wang" -- stay tuned, how to define function inside the "where" clause calcBmis :: (RealFloat a) => [(a, a)] -> [a] calcBmis xs = [bmi w h | (w, h) <- xs] where bmi weight height = weight / height ^ 2 -- in code above, bmi is defined inside the function 'calcBmis'