-- -- Exercises: Grab Bag -- 1. mTh x y z = x * y * z mTh' x y = \z -> x * y * z mTh'' x = \y -> \z -> x * y * z mTh''' = \x -> \y -> \z -> x * y * z -- They are all equivalent. -- It's like doing λabc.abc -- or λaλbλc.abc -- 2. -- mTh 3 :: Num a => a -> a -> a (d) -- 3. -- a. addOneIfOdd = \n -> case odd n of True -> f n False -> n where f n = n + 1 -- b. addFive = \x -> \y -> (if x > y then y else x) + 5 -- c. mFlip f x y = f y x newtype Username = Username String newtype AccountNumber = AccountNumber Integer data User = UnregisteredUser | RegisteredUser Username AccountNumber printUser :: User -> IO () printUser UnregisteredUser = putStrLn "UnregisteredUser" printUser (RegisteredUser (Username name) (AccountNumber acctNum)) = putStrLn $ name ++ " " ++ show acctNum data WherePenguinsLive = Galapagos | Antarctica | Australia | SouthAfrica | SouthAmerica deriving (Eq, Show) data Penguin = Peng WherePenguinsLive deriving (Eq, Show) isSouthAfrica :: WherePenguinsLive -> Bool isSouthAfrica SouthAfrica = True isSouthAfrica Galapagos = False isSouthAfrica Antarctica = False isSouthAfrica Australia = False isSouthAfrica SouthAmerica = False isSouthAfrica' :: WherePenguinsLive -> Bool isSouthAfrica' SouthAfrica = True isSouthAfrica' _ = False gimmeWhereTheyLive :: Penguin -> WherePenguinsLive gimmeWhereTheyLive (Peng whereitlives) = whereitlives humboldt = Peng SouthAmerica gentoo = Peng Antarctica macaroni = Peng Antarctica little = Peng Australia galapagos = Peng Galapagos galapagosPenguin :: Penguin -> Bool galapagosPenguin (Peng Galapagos) = True galapagosPenguin _ = False antarcticPenguin :: Penguin -> Bool antarcticPenguin (Peng Antarctica) = True antarcticPenguin _ = False antarcticOrGalapagos :: Penguin -> Bool antarcticOrGalapagos p = (galapagosPenguin p) || (antarcticPenguin p) addEmUp2 :: Num a => (a, a) -> a addEmUp2 (x, y) = x + y addEmUp2Alt :: Num a => (a, a) -> a addEmUp2Alt tup = (fst tup) + (snd tup) fst3 :: (a, b, c) -> a fst3 (x, _, _) = x third3 :: (a, b, c) -> c third3 (_, _, x) = x -- Exercises: Variety Pack -- 1. -- a) :t k :: (a, b) -> a -- b) :t k2 :: String. Different than k1 and k3 , which are (Num a => a) -- I guess they get defaulted to Integer by GCHI -- c) k3 (relabeled varietyPackK3) varietyPackK (x, y) = x varietyPackK1 = varietyPackK ((4 - 1), 10) varietyPackK2 = varietyPackK ("three", (1 + 2)) varietyPackK3 = varietyPackK (3, True) -- 2. varietyPackF :: (a, b, c) -> (d, e, f) -> ((a, d), (c, f)) varietyPackF (u, v, w) (x, y, z) = ((u, x), (w, z)) -- Exercises: Case Practice -- 1. -- functionC x y = if (x > y) then x else y functionC x y = case x > y of True -> x False -> y -- 2. -- ifEvenAdd2 n = if even n then (n+2) else n ifEvenAdd2 n = case even n of True -> (n + 2) False -> n -- 3. nums x = case compare x 0 of LT -> -1 EQ -> 0 GT -> 1 data Employee = Coder | Manager | Veep | CEO deriving (Eq, Ord, Show) reportBoss :: Employee -> Employee -> IO () reportBoss e e' = putStrLn $ show e ++ " is the boss of " ++ show e' employeeRank :: Employee -> Employee -> IO () employeeRank e e' = case compare e e' of GT -> reportBoss e e' EQ -> putStrLn "Neither employee\ \ is the boss" LT -> (flip reportBoss) e e' codersRuleCEOsDrool :: Employee -> Employee -> Ordering codersRuleCEOsDrool Coder Coder = EQ codersRuleCEOsDrool Coder _ = GT codersRuleCEOsDrool _ Coder = LT codersRuleCEOsDrool e e' = compare e e' employeeRank' :: (Employee -> Employee -> Ordering) -> Employee -> Employee -> IO () employeeRank' f e e' = case f e e' of GT -> reportBoss e e' EQ -> putStrLn "Neither employee\ \ is the boss" LT -> (flip reportBoss) e e' dodgy :: (Num a) => a -> a -> a dodgy x y = x + y * 10 oneIsOne :: (Num a) => a -> a oneIsOne = dodgy 1 oneIsTwo :: (Num a) => a -> a oneIsTwo = (flip dodgy) 2 dodgyOne = dodgy 1 0 == 1 dodgyTwo = dodgy 1 1 == 11 dodgyThree = dodgy 2 2 == 22 dodgyFour = dodgy 1 2 == 21 dodgyFive = dodgy 2 1 == 12 dodgySix = oneIsOne 1 == 11 dodgySeven = oneIsOne 2 == 21 dodgyEight = oneIsTwo 1 == 21 dodgyNine = oneIsTwo 2 == 22 dodgyTen = oneIsOne 3 == 31 dodgyEleven = oneIsTwo 3 == 23 allDone = foldl (\acc curr -> acc && curr) True [ dodgyOne , dodgyTwo , dodgyThree , dodgyFour , dodgyFive , dodgySix , dodgySeven , dodgyEight , dodgyNine , dodgyTen , dodgyEleven ] bloodNa :: Integer -> String bloodNa x | x < 135 = "too low" | x > 145 = "too high" | otherwise = "just right" isRight :: (Num a, Eq a) => a -> a -> a -> String isRight x y z | (x ^ 2) + (y ^ 2) == (z ^ 2) = "IS RIGHT" | otherwise = "not" dogYrs :: Integer -> Integer dogYrs x | x <= 0 = 0 | x <= 1 = x * 15 | x <= 2 = x * 12 | x <= 4 = x * 8 | otherwise = x * 6 -- Exercises: Guard Duty -- 1. avgGradeOne :: (Fractional a, Ord a) => a -> Char avgGradeOne x | otherwise = 'F' | y >= 0.9 = 'A' | y >= 0.8 = 'B' | y >= 0.7 = 'C' | y >= 0.59 = 'D' where y = x / 100 -- 2. avgGradeTwo :: (Fractional a, Ord a) => a -> Char avgGradeTwo x | y >= 0.7 = 'C' | y >= 0.9 = 'A' | y >= 0.8 = 'B' | y >= 0.59 = 'D' | otherwise = 'F' where y = x / 100 -- 3. palThree :: (Eq a) => [a] -> Bool palThree xs | xs == reverse xs = True | otherwise = False -- b) True when xs is a palindrome -- 4. a list of items that have instances of the Eq typeclass -- 5. see above for type -- 6. It returns c), an indication of whether its argument is a positive or negative number or zero -- 7. numbers takes arguments that have an instance of the Num and Ord type classes -- 8. numbers :: (Num a, Ord a) -> a -> a numbers :: (Num a, Ord a) => a -> a numbers x | x < 0 = -1 | x == 0 = 0 | x > 0 = 1 -- It claims _ is not matched. Why? arith2Add :: Int -> Int -> Int arith2Add x y = x + y arith2AddPF :: Int -> Int -> Int arith2AddPF = (+) arith2AddOne :: Int -> Int arith2AddOne x = (+) 1 x arith2AddOnePF :: Int -> Int arith2AddOnePF = (+ 1) print' = putStrLn . show arith2Main :: IO () arith2Main = do print' (0 :: Int) -- 0 print' (arith2Add 1 0) -- 1 print' (arith2AddOne 0) -- 1 print' (arith2AddOnePF 0) -- 1 print' ((arith2AddOne . arith2AddOne) 0) -- (\x -> 1 + ( 1 + x)) 0 == 2 print' ((arith2AddOnePF . arith2AddOne) 0) -- (\x -> (+) 1 (1 + x ) == 2 print' ((arith2AddOne . arith2AddOnePF) 0) -- (\x -> (1 + ((+1) x)) 0 == 2 print' ((arith2AddOnePF . arith2AddOnePF) 0) -- \(x -> (+1) ((+1) x)) 0 == 2 print' (negate (arith2AddOne 0)) -- negate ((+1) 0) == -1 print' ((negate . arith2AddOne) 0) -- (\x -> negate ((+1) x)) 0 == -1 print' ((arith2AddOne . arith2AddOne . arith2AddOne . negate . arith2AddOne) 0) -- (\x -> (1 + (1 + (1 + (negate (1 + x)))))) 0 == 2 -- Chapter exercises -- Multiple choice -- 1. d) A polymorphic function may resolve to values of different types, depending on inputs -- 2. b) Char -> [String] -- 3. d) (Ord a, Num a) => a -> Bool -- 4. b) is a higher-order function -- 5. a) f True :: Bool -- Let's write code ------------------- -- 1. tensDigit :: Integral a => a -> a tensDigit x = d where xLast = x `div` 10 d = xLast `mod` 10 -- a) tensDigit' :: Integral a => a -> a tensDigit' x = (flip mod) 10 . fst $ divMod x 10 -- b) yes hundreds :: Integral a => a -> a hundreds x = (flip mod) 100 . fst $ divMod x 100 -- c) -- Revisit this one -- 2. foldBoolPattern :: a -> a -> Bool -> a foldBoolPattern x _ False = x foldBoolPattern _ y True = y foldBoolGuard :: a -> a -> Bool -> a foldBoolGuard x y bool | not bool = x | bool = y -- writeCode3g :: (a -> b) -> (a, c) -> (b, c) writeCode3g f (x, y) = (f x, y) writeCode4RoundTrip :: (Show a, Read a) => a -> a writeCode4RoundTrip a = read (show a) -- It works because the showable thing gets converted to the string. -- And the string -- For this (Num a) => a type, roundTrip is an identity function. -- Are there data types that have instances of Show and Read that do not combine to the identity function writeCode4Main = do print (writeCode4RoundTrip 4) print (id 4) writeCode5RoundTrip :: (Show a, Read a) => a -> a writeCode5RoundTrip = read . show -- 6. writeCode6RoundTrip :: (Show a, Read b) => a -> b writeCode6RoundTrip = read . show -- print $ ((writeCode6RoundTrip 3) :: Int) -- Chapter definitions data SumOfThree a b c = FirstPossible a | SecondPossible b | ThirdPossible c deriving (Eq, Show) sumToInt :: SumOfThree a b c -> Integer sumToInt (FirstPossible _) = 0 sumToInt (SecondPossible _) = 1 sumToInt (ThirdPossible _) = 2 sumToInt' :: SumOfThree a b c -> Integer sumToInt' (FirstPossible _) = 0 sumToInt' _ = 1