lucky :: Int -> String
lucky 7 = "Lucky number seven!"
lucky x = "Sorry, you're out of luck, pal!"


factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial (n - 1)


addVectors :: (Double, Double) -> (Double, Double) -> (Double, Double)
addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)

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

second :: (a, b, c) -> b
second (_, y, _) = y

third :: (a, b, c) -> c
third (_, _, z) = z

head' :: [a] -> a
head' [] = error "Can't call head on an empty list, fool!"
head' (x:_) = x

head'2 :: [a] -> a
head'2 xs = 
  case xs of 
    [] -> error "No head for empty lists!"
    (x:_) -> x

tell :: (Show a) => [a] -> String
tell [] = "The list is empty"
tell (x:[]) = "The list has one element: " ++ show x
tell (x:y:[]) = "The list has two elements: " ++ show x ++ " and " ++ show y
tell (x:y:_) = "The list is long. The first two elements are: " ++ show x ++ " and " ++ show y


badAdd :: (Num a) => [a] -> a
badAdd [x,y,z] = x + y + z

firstLetter :: String -> String
firstLetter "" = "Emtpy string, whoops!"
firstLetter all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x]

bmiTell :: Double -> Double -> String
bmiTell weight height
  | bmi <= skinny = "You're underweight, you emo, you!"
  | bmi <= normal = "You're supposedly normal. Pfft, I bet you're ugly!"
  | bmi <= fat = "You're fat! Lose some weight, fatty!"
  | otherwise = "You're a whale, congratulations!"
  where (bmi, skinny, normal, fat) = (weight / height ^ 2, 18.5, 25.0, 30.0)

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

badGreeting :: String
badGreeting = "Oh! Pfft. It's you."

niceGreeting :: String
niceGreeting = "Hello! So very nice to see you,"

greet :: String -> String
greet "Juan" = niceGreeting ++ " Juan!"
greet "Fernando" = niceGreeting ++ " Fernando!"
greet name = badGreeting ++ " " ++ name

initials :: String -> String -> String
initials firstname lastname = [f] ++ ". " ++ [l] ++ "."
  where (f:_) = firstname
        (l:_) = lastname

initials2 :: String -> String -> String
initials2 (f:_) (l:_) = [f] ++ ". " ++ [l] ++ "."

calcBmis :: [(Double, Double)] -> [Double]
calcBmis [] = []
calcBmis ((weight, height):xs) = bmi:calcBmis xs
  where bmi = weight / height ^ 2

calcBmis2 :: [(Double, Double)] -> [Double]
calcBmis2 xs = [bmi w h| (w, h) <- xs]
  where bmi w h = w / h ^ 2

cylinder :: Double -> Double -> Double
cylinder r h =
  let sideArea = 2 * pi * r * h
      topArea = pi * r ^ 2
  in sideArea + 2 * topArea

calcBmis3 :: [(Double, Double)] -> [Double]
calcBmis3 xs = [bmi | (w, h) <- xs, let bmi = w / h ^ 2, bmi > 25.0]

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

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

sum' :: (Num a) => [a] -> a
sum' xs = foldl (\acc x -> acc + x) 0 xs
