--data Maybe a = Nothing | Just a

--instance (Eq a) => Eq (Maybe a) where
--  (Just x) == (Just y) = x == y
--  Nothing == Nothing = True
--  _ == _ = False

noises = [("dog","ruff"), ("cat","meow"), ("duck","quack"), ("cow","moo"), ("pig","oink"), ("lamb","baa")]

findKey :: Eq a => a -> [(a,b)] -> Maybe b
findKey _ [] = Nothing
findKey key ((x,y):zs) = if x == key then Just y else findKey key zs

thesaurus = [("silly","foolish"), ("stupid","dumb"), ("cold","frigid"), ("big","large"), ("happy","gay")]

synonym = (flip findKey) thesaurus

synonym' = (`findKey` thesaurus)

catMaybes :: [Maybe a] -> [a]
catMaybes [] = []
catMaybes ((Just x):xs) = x:(catMaybes xs)
catMaybes (Nothing:xs) = catMaybes xs

--catMaybes $ map synonym ["dumb","cold","hot","big"]

something (Just x) = True
something Nothing = False

catMaybes' = map (\(Just x) -> x) . filter something

mapMaybes :: (a -> Maybe b) -> [a] -> [b]
mapMaybes f [] = []
mapMaybes f (x:xs) =
  case f x of
    (Just y) -> y:(mapMaybes f xs)
    (Nothing) -> mapMaybes f xs

--mapMaybes synonym ["dumb","cold","hot","big"]

mapMaybes' f = catMaybes . map f

x % y = if y == 0 then Nothing else Just (x / y)

maybeSqrt (Just x) = Just $ sqrt x
maybeSqrt (Nothing) = Nothing

lift1 :: (a -> b) -> Maybe a -> Maybe b
lift1 f (Just x) = Just $ f x
lift1 _ Nothing  = Nothing

maybeSqrt' = lift1 sqrt

--sqrt (7 % 2)

--instance Functor Maybe where
--    fmap f (Just x) = Just $ f x
--    fmap _ Nothing  = Nothing

lift2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
lift2 f (Just x) (Just y)  = Just $ f x y
lift2 f _  _ = Nothing

--lift2 (+) (7 % 2) (3 % 4)

instance (Num a) => Num (Maybe a) where
    (+) = lift2 (+)
    (*) = lift2 (*)
    abs = fmap abs
    signum = fmap signum

instance (Eq a, Fractional a) => Fractional (Maybe a) where
    (Just _) / (Just 0) = Nothing
    (Just x) / (Just y) = Just $ x / y
    _ / _  = Nothing

--divList xs = foldr1 (/) $ map Just xs

divList = foldr1 (/) . map Just