-- Examples from chapter 4
-- http://learnyouahaskell.com/syntax-in-functions

lucky :: (Integral a) => a -> String  
lucky 7 = "LUCKY NUMBER SEVEN!"  
lucky x = "Sorry, you're out of luck, pal!"

factorial :: (Integral a) => a -> a
factorial 0 = 1
factorial x = x * factorial (x - 1)

addVectors :: (Num a) => (a, a) -> (a, a) -> (a, a)
addVectors (a1, a2) (b1, b2) = (a1 + b1, a2 + b2)

first :: (a, b, c) -> a
first (x, _, _) = x

head' :: [a] -> a
head' [] = error "Err"
head' (x:_) = x

tell :: (Show a) => [a] -> String
tell [] = "Empty"
tell (x:[]) = "One element: " ++ show x
tell (x:y:[]) = "Two elements: " ++ show x ++ " and " ++ show y
tell (x:y:_) = "More than two elements. First are " ++ show x ++ " and " ++ show y

tell' :: (Show a) => [a] -> String
tell' [] = "Empty"
tell' [x] = "One element: " ++ show x
tell' [x, y] = "Two elements: " ++ show x ++ " and " ++ show y
tell' (x:y:_) = "More than two elements. First are " ++ show x ++ " and " ++ show y

bmiTell :: (RealFloat a) => a -> a-> String
bmiTell weight height
    | bmi <= 18.5 = "Underweight"
    | bmi <= 25.0 = "Normal"
    | bmi <= 30.0 = "Overweight"
    | otherwise = "Obese"
    where bmi = weight / height ^ 2

cylinder :: (RealFloat a) => a -> a -> a
cylinder r h =
    let sideArea = 2 * pi * r * h
        topArea = pi * r ^ 2
    in sideArea + 2 * topArea

describeList1 :: [a] -> String
describeList1 xs = "The list is " ++ case xs of [] -> "empty"
                                                [x] -> "a singleton"
                                                xs -> "a longer list"

describeList2 :: [a] -> String
describeList2 xs = "The list is " ++ what xs
    where what [] = "empty"
          what [x] = "a singleton"
          what xs = "a longer list"
