Koans
1. Ninety-nine Haskell Problems
These are Haskell translations of Ninety-Nine Lisp Problems. 1
1.1. Problem 1
myLast :: [a] -> a myLast xs = last xs
1.2. Problem 2
myButLast :: [a] -> a myButLast = last . init
1.3. Problem 3
elementAt :: [a] -> Int -> a elementAt xs num = last $ take num xs
1.4. Problem 4
myLength :: [a] -> Int myLength [] = 0 myLength (_:xs) = 1 + myLength xs
1.5. Problem 5
myReverse :: [a] -> [a] myReverse [] = [] myReverse (x:xs) = myReverse xs ++ [x]
1.6. Problem 6
isPalindrome :: Eq a => [a] -> Bool isPalindrome xs = if xs == reverse xs then True else False
1.7. Problem 7
data NestedList a = Elem a | List [NestedList a] flatten :: NestedList a -> [a] flatten (Elem e) = [e] flatten (List (x:xs)) = flatten x ++ flatten (List xs) flatten (List []) = []
1.8. Problem 8
compress :: Eq a => [a] -> [a] compress [] = [] compress (x:xs) = x : (compress $ filter (/= x) xs)
1.9. Problem 9, 10
pack :: Eq a => [a] -> [[a]] pack [] = [] pack (x:xs) = (x : takeWhile (==x) xs) : pack (dropWhile (==x) xs) encode :: Eq a => [a] -> [(Int, a)] encode [] = [] encode xs = count p where p = pack xs count [] = [] count (x:xs) = (length x, head x) : count xs
1.10. Problem 11
data EncodedData a = Single a | Multiple Int a deriving (Show) pack :: (Eq a) => [a] -> [[a]] pack [] = [] pack (x:xs) = [x : takeWhile (==x) xs] ++ pack (dropWhile (==x) xs) encodeModified :: (Eq a) => [a] -> [EncodedData a] encodeModified = encode . pack where encode [] = [] encode (x:xs) = if length x == 1 then Single (head x) : encode xs else Multiple (length x) (head x) : encode xs
1.11. Problem 12
data EncodedData a = Single a | Multiple Int a deriving (Show) decodeModified :: Eq a => [EncodedData a] -> [a] decodeModified = concatMap decode where decode (Single x) = [x] decode (Multiple n x) = replicate n x
1.12. Problem 13
data EncodedData a = Single a | Multiple Int a deriving (Show) encodeDirect :: (Eq a) => [a] -> [EncodedData a] encodeDirect [] = [] encodeDirect (x:xs) = if (head xs) /= x then Single x : encodeDirect xs else Multiple (((+1) . length . takeWhile (==x)) xs) x : encodeDirect (dropWhile (==x) xs)
1.13. Problem 14
dupli :: [a] -> [a] dupli [] = [] dupli (x:xs) = x : x : dupli xs
1.14. Problem 15
repli :: [a] -> Int -> [a] repli [] _ = [] repli (x:xs) n = replicate n x ++ repli xs n
1.15. Problem 16
dropEvery :: [a] -> Int -> [a] dropEvery [] _ = [] dropEvery xs n = dhelper xs n n where dhelper [] _ _ = [] dhelper (x:xs) n 1 = dhelper xs n n dhelper (x:xs) n m = x : (dhelper xs n (m - 1))
1.16. Problem 17
split :: [a] -> Int -> ([a], [a]) split [] _ = ([], []) split l@(x:xs) n = if n > 0 then (x : ys, zs) else ([], l) where (ys, zs) = split xs (n - 1)
1.17. Problem 18
slice :: [a] -> Int -> Int -> [a] slice [] _ _ = [] slice l start end = if start >= end then l else drop (start - 1) $ take end l
1.18. Problem 19
rotate :: [a] -> Int -> [a] rotate [] _ = [] rotate xs n | abs n >= length xs = xs | n >= 0 = drop n xs ++ take n xs | otherwise = drop trunk xs ++ take trunk xs where trunk = length xs + n
1.19. Problem 20
removeAt :: Int -> [a] -> (Maybe a, [a]) removeAt _ [] = (Nothing, []) removeAt ith xs | ith > length xs || ith <= 0 = (Nothing, xs) | otherwise = (Just cha, str) where cha = (last . (take ith)) xs str = (take (ith-1) xs) ++ (drop ith xs)
1.20. Problem 21
insertAt :: a -> [a] -> Int -> [a] insertAt ch xs i | i <= 0 = ch : xs | i > length xs = xs ++ [ch] | otherwise = (take (i-1) xs) ++ [ch] ++ (drop (i-1) xs)
1.21. Problem 22
range :: (Enum a, Ord a) => a -> a -> [a] range i j | i > j = [] | otherwise = helper [i] j where helper xs j | last xs == j = xs | otherwise = helper (xs ++ [(succ . last) xs]) j
1.22. Problem 23
import System.Random (randomRIO) rnd_select :: [a] -> Int -> IO [a] rnd_select xs n | n < 0 = error "N must be greater than zero." | n == 0 = return [] | otherwise = do r <- randomRIO (1, length xs) rest <- rnd_select (init (take r xs) ++ drop r xs) (n - 1) return $ (xs !! (r - 1)) : rest
1.23. Problem 24
import System.Random (randomRIO) diff_select :: Int -> Int -> IO [Int] diff_select n m | m < 1 = error "M must be greater than 1" | n > m = error "N must be less than M" | otherwise = helper n [1..m] where helper :: Int -> [Int] -> IO [Int] helper n xs = if n <= 0 then return [] else do r <- randomRIO (1, length xs) rest <- helper (n - 1) (init (take r xs) ++ drop r xs) return $ (xs !! (r - 1)) : rest
1.24. Problem 25
import System.Random (randomRIO) rnd_permu :: [a] -> IO [a] rnd_permu xs | length xs == 0 = return [] | otherwise = do r <- randomRIO (1, length xs) rest <- rnd_permu $ (init $ take r xs) ++ drop r xs return $ xs !! (r - 1) : rest
1.25. Problem 26
combinations :: Int -> [a] -> [[a]] combinations 0 _ = [[]] combinations _ [] = [[]] combinations i (x:xs) = x_start ++ others where x_start = [x : rest | rest <- combinations (i-1) xs] others = if i <= length xs then combinations i xs else []
1.26. Problem 27
import Data.List import Data.Ord (comparing) combination :: Int -> [a] -> [([a], [a])] combination 0 xs = [([], xs)] combination n [] = [] combination n (x:xs) = ts ++ ds where ts = [ (x:ys, zs) | (ys, zs) <- combination (n-1) xs ] ds = [ (ys, x:zs) | (ys, zs) <- combination n xs ] group :: [Int] -> [a] -> [[[a]]] group [] _ = [[]] group (n:ns) xs = [ g:gs | (g, rs) <- combination n xs , gs <- group ns rs ]
1.27. Problem 28
import Data.List import Data.Ord (comparing) lsort :: [[a]] -> [[a]] lsort = sortBy (comparing length) lfsort :: [[a]] -> [[a]] lfsort lists = concat groups where groups = lsort $ groupBy equalLength $ lsort lists equalLength xs ys = length xs == length ys
1.28. Problem 31
isPrime :: Integral a => a -> Bool isPrime n | n < 2 = error "Error!" | n == 2 = True | otherwise = pprime [2..n] where pprime (x:xs) | xs == [] = True | mod (last xs) x == 0 = False | otherwise = pprime xs
1.29. Problem 32
myGCD :: Integral a => a -> a -> a myGCD x y = helper x' y' where x' = maximum [abs x, abs y] -- greater one y' = minimum [abs x, abs y] -- less one helper a b = let m = mod a b in if m == 0 then b else helper b m
1.30. Problem 33, 34
coprime :: Integral a => a -> a -> Bool coprime x y = if gcd x y == 1 then True else False totient :: Int -> Int totient x | abs x == 0 = error "Error." | otherwise = length primes where x' = abs x primes = filter (coprime x') [1..x']
1.31. Problem 35, 36, 37
import Data.List primeFactors :: Integral a => a -> [a] primeFactors n = if n == 1 || ps' == [] then [] else head ps' : primeFactors (div n' (head ps')) where primes = filterPrime [2..] where filterPrime (p:xs) = p : filterPrime [x | x <- xs, mod x p /= 0] n' = abs n ps = filter (<= n') primes ps' = filter ((==0) . mod n') ps prime_factors_mult :: Int -> [(Int, Int)] prime_factors_mult x = concatMap (\x -> [(x, pcount x ps)]) ups where ps = primeFactors x ups = nub ps pcount p ps = length $ filter (==p) ps totient m = product [(p - 1) * p ^ (c - 1) | (p, c) <- prime_factors_mult m]
1.32. Problem 39, 40, 41
import Data.Maybe isPrime :: Integral a => a -> Bool isPrime n | n < 2 = error "Error!" | n == 2 = True | otherwise = pprime [2..n] where pprime (x:xs) | xs == [] = True | mod (last xs) x == 0 = False | otherwise = pprime xs primesR :: Integral a => a -> a -> [a] primesR x y | x > y || x < 2 = error "Error!!!" | otherwise = [x | x <- [x..y], isPrime x] goldbach :: Integral a => a -> Maybe (a, a) goldbach n = if l == [] then Nothing else Just $ head l where l = [(x, y) | x <- pr, y <- pr, x + y == n] pr = primesR 2 (n-2) goldbachList :: Integral a => a -> a -> Maybe [(a, a)] goldbachList x y | x > y = Nothing | otherwise = Just s where s = [(fromJust . goldbach) a | a <- [x..y], (not . isNothing . goldbach) a, even a]
1.33. Problem 46, 47, 48
import Control.Monad (replicateM) and' :: Bool -> Bool -> Bool and' True True = True and' _ _ = False or' :: Bool -> Bool -> Bool or' False False = False or' _ _ = True equ' :: Bool -> Bool -> Bool equ' False False = True equ' True True = True equ' _ _ = False table :: (Bool -> Bool -> Bool) -> IO () table f = putStrLn $ concatMap (++ "\n") [show a ++ " " ++ show b ++ " " ++ show (f a b) | a <- [True, False], b <- [True, False]] -- Problem 47 infixl 4 `or'` infixl 6 `and'` table2 = table -- Problem 48 infixl 3 `equ'` tablen :: Int -> ([Bool] -> Bool) -> IO () tablen n f = mapM_ putStrLn [toStr a ++ " " ++ show (f a) | a <- args n] where args n = replicateM n [True, False] toStr = unwords . map (\x -> show x)
1.34. Problem 49
import Control.Monad (replicateM) gray :: Int -> [[Char]] gray x = replicateM x ['0', '1']
1.35. Problem 50
import Data.List import Data.Ord (comparing) data HTree a = Leaf a | Branch (HTree a) (HTree a) deriving Show huffman :: (Ord a, Ord w, Num w) => [(a, w)] -> [(a, [Char])] huffman freq = sortBy (comparing fst) $ serialize $ htree $ sortBy (comparing fst) $ [(w, Leaf x) | (x, w) <- freq] where htree [(_, t)] = t htree ((w1, t1) : (w2, t2) : wts) = htree $ insertBy (comparing fst) (w1 + w2, Branch t1 t2) wts serialize (Branch l r) = [(x, '0':code) | (x, code) <- serialize l] ++ [(x, '1':code) | (x, code) <- serialize r] serialize (Leaf x) = [(x, "")]
1.36. Problem 55, 56, 57, 58, 59, 60
import Data.List import Data.Maybe (fromJust) data Tree a = Empty | Branch a (Tree a) (Tree a) deriving (Show, Eq) cbalTree :: Int -> [Tree Char] cbalTree 0 = [Empty] cbalTree n = let (q, r) = (n - 1) `quotRem` 2 in [Branch 'x' left right | i <- [q .. q + r], left <- cbalTree i, right <- cbalTree (n - i - 1)] mirror :: Tree a -> Tree a -> Bool mirror Empty Empty = True mirror (Branch _ l r) (Branch _ l' r') = mirror l r' && mirror r l' mirror _ _ = False symmetric :: Tree a -> Bool symmetric t = mirror t t -- Binary Search Tree construct :: Integral a => [a] -> Tree a construct [] = Empty construct (x:xs) = let (l, r) = partition (< x) xs in Branch x (construct l) (construct r) -- BST ends here. symCbalTree :: Int -> [Tree Char] symCbalTree = (filter symmetric) . cbalTree hbalTree :: a -> Int -> [Tree a] hbalTree x 0 = [Empty] hbalTree x 1 = [Branch x Empty Empty] hbalTree x h = [Branch x l r | (hl, hr) <- [(h-2, h-1), (h-1, h-1), (h-1, h-2)], l <- hbalTree x hl, r <- hbalTree x hr] hbalTreeNodes :: a -> Int -> [Tree a] hbalTreeNodes _ 0 = [Empty] hbalTreeNodes x n = concatMap toFilteredTrees [minHeight .. maxHeight] where toFilteredTrees = filter ((n ==) . countNodes) . hbalTree x minNodesSeq = 0:1:zipWith ((+) . (+1)) minNodesSeq (tail minNodesSeq) minNodes = (minNodesSeq !!) minHeight = ceiling $ logBase 2 $ fromIntegral (n+1) maxHeight = (fromJust $ findIndex (>n) minNodesSeq) - 1 countNodes Empty = 0 countNodes (Branch _ l r) = 1 + countNodes l + countNodes r
1.37. Problem 61, 62, 63
data Tree a = Empty | Branch a (Tree a) (Tree a) deriving (Show, Eq) tree4 = Branch 1 (Branch 2 Empty (Branch 4 Empty Empty)) (Branch 2 Empty Empty) countLeaves :: Tree a -> Integer countLeaves Empty = 0 countLeaves (Branch _ Empty Empty) = 1 countLeaves (Branch _ l r) = countLeaves l + countLeaves r leaves :: Tree a -> [a] leaves Empty = [] leaves (Branch x Empty Empty) = [x] leaves (Branch _ l r) = leaves l ++ leaves r internals :: Tree a -> [a] internals Empty = [] internals (Branch _ Empty Empty) = [] internals (Branch x l r) = x : (internals l ++ internals r) atLevel :: Tree a -> Int -> [a] atLevel Empty _ = [] atLevel (Branch x l r) n = if n == 1 then [x] else atLevel l (n-1) ++ atLevel r (n-1) completeBinaryTree :: Int -> Tree Char completeBinaryTree n = generate_tree 1 where generate_tree x = if x > n then Empty else Branch 'x' (generate_tree (2*x)) (generate_tree (2*x+1)) calCompleteHeight :: Tree Char -> Maybe Int calCompleteHeight Empty = Just 0 calCompleteHeight (Branch _ l r) = do hr <- calCompleteHeight r hl <- calCompleteHeight l if (hl == hr) || (hl - hr == 1) then return $ 1 + hl else Nothing isCompleteBinaryTree = (/= Nothing) . calCompleteHeight
1.38. Problem 64
data Tree a = Empty | Branch a (Tree a) (Tree a) deriving (Show, Eq) tree64 = Branch 'n' (Branch 'k' (Branch 'c' (Branch 'a' Empty Empty) (Branch 'h' (Branch 'g' (Branch 'e' Empty Empty) Empty ) Empty ) ) (Branch 'm' Empty Empty) ) (Branch 'u' (Branch 'p' Empty (Branch 's' (Branch 'q' Empty Empty) Empty ) ) Empty ) type Pos = (Int, Int) layout :: Tree a -> Tree (a, Pos) layout t = fst (layoutHelper 1 1 t) where layoutHelper x y Empty = (Empty, x) layoutHelper x y (Branch a l r) = (Branch (a, (x', y)) l' r', x'') where (l', x') = layoutHelper x (y+1) l (r', x'') = layoutHelper (x'+1) (y+1) r
2. Exercises of Haskell Programming from First Principles
2.1. Chapter 10
-- 10.10 -- Given the following sets of consonants and vowels... -- 1 stops = "pbtdkg" vowels = "aeiou" -- a) triples stops vowels = [(x, y, z) | x <- stops, y <- vowels, z <- stops] -- b) triplesP stops vowels = [(x, y, z) | x <- stops, y <- vowels, z <- stops, x == 'p'] -- c) nouns = ["cat", "dog", "banana"] verbs = ["love", "kiss", "like"] nounVerbNoun nouns verbs = [n ++ " " ++ v ++ " " ++ n' | n <- nouns, v <- verbs, n' <- nouns] -- 2 -- this function calculates the average number of letters every word contains avgWordLength x = (/) (fromIntegral letterNum) (fromIntegral wordNum) where letterNum = (sum (map length (words x))) wordNum = (length (words x)) -- rewrite functions using folds -- 1 myOr :: [Bool] -> Bool myOr = foldr (||) False -- 2 myAny :: (a -> Bool) -> [a] -> Bool myAny f = foldr ((||) . f) False -- 3 myElem :: Eq a => a -> [a] -> Bool myElem n = foldr ((||) . (==) n) False -- 4 myReverse :: [a] -> [a] myReverse = foldl (flip (:)) [] -- 5 myMap :: (a -> b) -> [a] -> [b] myMap f = foldr ((:) . f) [] -- 6 myFilter :: (a -> Bool) -> [a] -> [a] myFilter f = foldr (\x y -> if (f x) then x : y else y) [] -- 7 squish :: [[a]] -> [a] squish = foldr (++) [] -- 8 squishMap :: (a -> [b]) -> [a] -> [b] squishMap f = foldr ((++) . f) [] -- 9 squishAgain :: [[a]] -> [a] squishAgain = squishMap id -- 10 myMaximumBy :: (a -> a -> Ordering) -> [a] -> a myMaximumBy f xs = foldr (\x y -> if f x y == GT then x else y) (last xs) xs -- 11 myMinimumBy :: (a -> a -> Ordering) -> [a] -> a myMinimumBy f xs = foldr (\x y -> if f x y == LT then x else y) (last xs) xs
2.2. Chapter 11
data Price = Price Integer deriving (Eq, Show) data Manufacturer = Mini | Mazda | Tata deriving (Eq, Show) data Airline = PapuAir | CatapultsR'Us | TakeYourChancesUnited deriving (Eq, Show) data Vehicle = Car Manufacturer Price | Plane Airline deriving (Eq, Show) myCar = Car Mini (Price 14000) urCar = Car Mazda (Price 20000) clownCar = Car Tata (Price 7000) doge = Plane PapuAir isCar :: Vehicle -> Bool isCar (Car _ _) = True isCar (Plane _) = False isPlane :: Vehicle -> Bool isPlane (Car _ _) = False isPlane (Plane _) = True areCars :: [Vehicle] -> [Bool] areCars = map isCar getManu :: Vehicle -> Manufacturer getManu (Car m _) = m
data OperatingSystem = GnuPlusLinux | OpenBSDPlusNevermindJustBSDStill | Mac | Windows deriving (Eq, Show) data ProgrammingLanguage = Haskell | Agda | Idris | PureScript deriving (Eq, Show) data Programmer = Programmer { os :: OperatingSystem , lang :: ProgrammingLanguage } deriving (Eq, Show) allOperatingSystems :: [OperatingSystem] allOperatingSystems = [ GnuPlusLinux , OpenBSDPlusNevermindJustBSDStill , Mac , Windows ] allLanguages :: [ProgrammingLanguage] allLanguages = [ Haskell , Agda , Idris , PureScript ] allProgrammers :: [Programmer] allProgrammers = [Programmer { os = o, lang = l} | o <- allOperatingSystems , l <- allLanguages]
-- Write map for BinaryTree data BinaryTree a = Leaf | Node (BinaryTree a) a (BinaryTree a) deriving(Ord, Eq, Show) mapTree :: (a -> b) -> BinaryTree a -> BinaryTree b mapTree _ Leaf = Leaf mapTree f (Node left a right) = Node (mapTree f left) (f a) (mapTree f right) testTree' :: BinaryTree Integer testTree' = Node (Node Leaf 3 Leaf) 1 (Node Leaf 4 Leaf) mapExpected = Node (Node Leaf 4 Leaf) 2 (Node Leaf 5 Leaf) mapOkay = if mapTree (+1) testTree' == mapExpected then print "yup okay!" else error "test failed!" -- Convert binarry trees to lists preorder :: BinaryTree a -> [a] preorder Leaf = [] preorder (Node left b right) = [b] ++ (preorder left) ++ (preorder right) inorder :: BinaryTree a -> [a] inorder Leaf = [] inorder (Node left b right) = (inorder left) ++ [b] ++ (inorder right) postorder :: BinaryTree a -> [a] postorder Leaf = [] postorder (Node left b right) = (postorder left) ++ (postorder right) ++ [b] testTree :: BinaryTree Integer testTree = Node (Node Leaf 1 Leaf) 2 (Node Leaf 3 Leaf) testPreorder :: IO () testPreorder = if preorder testTree == [2, 1, 3] then putStrLn "Preorder succeeded!" else putStrLn "Preorder failed!" testInorder :: IO () testInorder = if inorder testTree == [1, 2, 3] then putStrLn "Inorder succeeded!" else putStrLn "Inorder failed!" testPostorder :: IO () testPostorder = if postorder testTree == [1, 3, 2] then putStrLn "Postorder succeeded!" else putStrLn "Postorder failed!" -- Write foldr for BinaryTree foldTree :: (a -> b -> b) -> b -> BinaryTree a -> b foldTree f b bt = foldr f b (preorder bt) testFoldTree :: IO () testFoldTree = if (foldTree (+) 1 testTree == 7) then putStrLn "foldTree succeeded!" else putStrLn "foldTree failed!"
import Data.Char -- 1 isSubsequenceOf :: (Eq a) => [a] -> [a] -> Bool isSubsequenceOf [] _ = True isSubsequenceOf _ [] = False isSubsequenceOf xa@(x:xs) (y:ys) = if x == y then isSubsequenceOf xs ys else isSubsequenceOf xa ys -- 2 capitalizeWords :: String -> [(String, String)] capitalizeWords [] = [] capitalizeWords s = [(w, ((toUpper . head $ w) : tail w)) | w <- (words s)]
import Data.Char -- 1 capitalizeWord :: String -> String capitalizeWord [] = [] capitalizeWord (w:ws) = toUpper w : ws -- 2 capitalizeParagraph :: String -> String capitalizeParagraph = go True where go _ [] = [] go doIt (' ':cs) = ' ' : go doIt cs go doIt ('.':cs) = '.' : go True cs go False (c:cs) = c : go False cs go True (c:cs) = toUpper c : go False cs
import Data.Char import Data.List -- 1 type Digit = Char type Presses = Int data Button = Button Digit String deriving (Show) data DaPhone = DaPhone [Button] deriving (Show) phone :: DaPhone phone = DaPhone [ Button '1' "1" , Button '2' "abc2" , Button '3' "def3" , Button '4' "ghi4" , Button '5' "jkl5" , Button '6' "mno6" , Button '7' "pqrs7" , Button '8' "tuv8" , Button '9' "wxyz9" , Button '*' "" , Button '0' " 0" , Button '#' "." ] -- 2 convo :: [String] convo = [ "Wanna play 20 questions" , "Ya" , "U 1st haha" , "Lol ok. Have u ever tasted alcohol lol" , "Lol ya" , "Wow ur cool haha. Ur turn" , "Ok. Do u think I am pretty Lol" , "Lol ya" , "Haha thanks just making sure rofl ur turn" ] containCharacter :: Char -> Button -> Bool containCharacter x (Button y ys) = (toLower x) `elem` ys findButton :: DaPhone -> Char -> Button findButton (DaPhone buttons) x = head $ filter (containCharacter x) buttons numberOfPresses :: String -> Char -> Presses numberOfPresses [] _ = 0 numberOfPresses (x:xs) y = if x == toLower y then 1 else 1 + numberOfPresses xs y reverseTaps :: DaPhone -> Char -> [(Digit, Presses)] reverseTaps phone x = uppercaseTap ++ digitTap where (Button digit chars) = findButton phone x uppercaseTap = if isUpper x then [('*', 1)] else [] digitTap = [(digit, numberOfPresses chars x)] flatten :: [[a]] -> [a] flatten = foldr (++) [] cellPhonesDead :: DaPhone -> String -> [(Digit, Presses)] cellPhonesDead p = flatten . map (reverseTaps p) -- 3 fingerTaps :: [(Digit, Presses)] -> Presses fingerTaps = sum . map snd -- 4 countLetters :: String -> Char -> Int countLetters str c = length $ filter (== c) str mostPopularLetter :: String -> Char mostPopularLetter [] = '\x0' mostPopularLetter str = fst $ head $ filter ((== mx) . snd) lc where lc = [(e, countLetters str e) | e <- nub str] mx = maximum $ map snd lc countWords :: String -> String -> Int countWords str w = length $ filter (== w) (words str) mostPopularWord :: String -> String mostPopularWord [] = "\x0" mostPopularWord str = fst $ head $ filter ((== mx) . snd) lc where lc = [(e, countWords str e) | e <- nub $ words str] mx = maximum $ map snd lc coolestLtr :: [String] -> Char coolestLtr = mostPopularLetter . flatten coolestWord :: [String] -> String coolestWord = mostPopularWord . flatten
data Expr = Lit Integer | Add Expr Expr eval :: Expr -> Integer eval (Lit i) = i eval (Add e e') = (eval e) + (eval e') printExpr :: Expr -> String printExpr (Lit i) = show i printExpr (Add e e') = (printExpr e) ++ " + " ++ (printExpr e')
2.3. Chapter 12
-- 12.5 Chapter Exercises import Data.Char import Data.List -- String processing -- 1 notThe :: String -> Maybe String notThe w = if w /= "the" then Just w else Nothing vowels = "aeiou" replaceThe :: String -> String replaceThe s = unwords $ map (sub . notThe) (words s) where sub Nothing = "a" sub (Just w) = w -- 2 countTheBeforeVowel :: String -> Integer countTheBeforeVowel [] = 0 countTheBeforeVowel s = if length w <= 1 then 0 else if w!!0 == "the" && (w!!1)!!0 `elem` vowels then 1 + (countTheBeforeVowel s') else countTheBeforeVowel s' where w = words s s' = unwords $ drop 1 w -- 3 countVowels :: String -> Integer countVowels [] = 0 countVowels (c:cs) = if (toLower c) `elem` vowels then 1 + countVowels cs else countVowels cs -- Another solution countVowels' :: String -> Integer countVowels' = sum . map (\x -> if (toLower x) `elem` vowels then 1 else 0) -- Validate the word consonants = ['a'..'z'] \\ vowels countConsonants :: String -> Integer countConsonants = sum . map (\x -> if (toLower x) `elem` consonants then 1 else 0) newtype Word' = Word' String deriving (Eq, Show) mkWord :: String -> Maybe Word' mkWord str = if vn > cn then Nothing else Just (Word' str) where vn = countVowels str cn = countConsonants str
-- It's only Natural data Nat = Zero | Succ Nat deriving (Eq, Show) natToInteger :: Nat -> Integer natToInteger Zero = 0 natToInteger (Succ n) = 1 + (natToInteger n) integerToNat :: Integer -> Maybe Nat integerToNat i | i < 0 = Nothing | i == 0 = Just Zero | otherwise = fmap Succ (integerToNat (i - 1))
-- Small library for Maybe -- 1 isJust :: Maybe a -> Bool isJust Nothing = False isJust (Just _) = True isNothing :: Maybe a -> Bool isNothing Nothing = True isNothing (Just _) = False -- 2 mayybee :: b -> (a -> b) -> Maybe a -> b mayybee m _ Nothing = m mayybee _ f (Just n) = f n -- 3 fromMaybe :: a -> Maybe a -> a fromMaybe m Nothing = m fromMaybe _ (Just n) = n -- 4 listToMaybe :: [a] -> Maybe a listToMaybe [] = Nothing listToMaybe (x:xs) = Just x maybeToList :: Maybe a -> [a] maybeToList Nothing = [] maybeToList (Just x) = [x] -- 5 catMaybes :: [Maybe a] -> [a] catMaybes = concatMap m2l where m2l Nothing = [] m2l (Just x) = [x] -- 6 flipMaybe :: [Maybe a] -> Maybe [a] flipMaybe xs = ck $ catMaybes xs where ck [] = Nothing ck x = Just x
-- Small library for Either -- 1 lefts' :: [Either a b] -> [a] lefts' = foldr pickLeft [] where pickLeft (Right x) l = l pickLeft (Left x) l = x:l -- 2 rights' :: [Either a b] -> [b] rights' = foldr pickRight [] where pickRight (Right x) l = x:l pickRight (Left x) l = l -- 3 partitionEithers' :: [Either a b] -> ([a], [b]) partitionEithers' xs = (lefts' xs, rights' xs) -- 4 eitherMaybe' :: (b -> c) -> Either a b -> Maybe c eitherMaybe' _ (Left x) = Nothing eitherMaybe' f (Right x) = Just (f x) -- 5 either' :: (a -> c) -> (b -> c) -> Either a b -> c either' f _ (Left x) = f x either' _ f (Right x) = f x -- 6 eitherMaybe'' :: (b -> c) -> Either a b -> Maybe c eitherMaybe'' f = either' (\_ -> Nothing) (Just . f)
-- Write your own iterate and unfoldr myIterate :: (a -> a) -> a -> [a] myIterate f x = [x] ++ (myIterate f (f x)) myUnfoldr :: (b -> Maybe (a, b)) -> b -> [a] myUnfoldr f x = [pickFst (f x)] ++ (myUnfoldr f (pickSnd (f x))) where pickFst :: Maybe (a, b) -> a pickFst (Just (x, y)) = x pickSnd :: Maybe (a, b) -> b pickSnd (Just (x, y)) = y betterIterate :: (a -> a) -> a -> [a] betterIterate f x = myUnfoldr (\x -> Just (x, (f x))) x
-- Finally something other than a list! data BinaryTree a = Leaf | Node (BinaryTree a) a (BinaryTree a) deriving (Eq, Ord, Show) -- 1 -- unfold (\x -> Myabe (x, x+1, x)) 0 unfold :: (a -> Maybe (a, b, a)) -> a -> BinaryTree b unfold f a = case f a of Nothing -> Leaf Just (x, y, z) -> Node (unfold f x) y (unfold f z) -- 2 treeBuild :: Integer -> BinaryTree Integer treeBuild n = unfold treeHelper 0 where treeHelper a | a < n = Just (a+1, a , a+1) | otherwise = Nothing
2.4. Chapter 15
-- Optional monoid import Data.Monoid data Optional a = Nada | Only a deriving (Eq, Show) instance Monoid a => Monoid (Optional a) where mempty = Nada mappend (Only x) Nada = Only x mappend Nada (Only x) = Only x mappend (Only x) (Only y) = Only (mappend x y)
2.5. Chapter 16
-- Exercises: Heavy Lifting a = fmap (+1) $ read "[1]" :: [Int] b = (fmap . fmap) (++ "lol") (Just ["Hi,", "Hello"]) c = fmap (*2) (\x -> x - 2) d = fmap ((return '1' ++) . show) (\x -> [x, 1..3]) e :: IO Integer e = let ioi = readIO "1" :: IO Integer changed = fmap read $ fmap ("123"++) $ fmap show ioi in fmap (*3) changed
-- 16.10 Exercises: Instances of Func -- 1 newtype Identity a = Identity a deriving (Eq, Show) instance Functor Identity where fmap f (Identity a) = Identity (f a) -- 2 data Pair a = Pair a a deriving (Eq, Show) instance Functor Pair where fmap f (Pair a b) = Pair (f a) (f b) -- 3 data Two a b = Two a b deriving (Eq, Show) instance Functor (Two a) where fmap f (Two a b) = Two a (f b) -- 4 data Three a b c = Three a b c deriving (Eq, Show) instance Functor (Three a b) where fmap f (Three a b c) = Three a b (f c) -- 5 data Three' a b = Three' a b b deriving (Eq, Show) instance Functor (Three' a) where fmap f (Three' a b c) = Three' a (f b) (f c) -- 6 data Four a b c d = Four a b c d deriving (Eq, Show) instance Functor (Four a b c) where fmap f (Four a b c d) = Four a b c (f d) -- 7 data Four' a b = Four' a a a b deriving (Eq, Show) instance Functor (Four' a) where fmap f (Four' a b c d) = Four' a b c (f d) -- 8 -- Trivial cannot be implemented because it has kind * while a Functor -- instance requires a kind * -> *
-- Exercise: Possibly data Possibly a = LolNope | Yeppers a deriving (Eq, Show) instance Functor Possibly where fmap f (Yeppers a) = Yeppers (f a) fmap f LolNope = LolNope -- Short Exercise -- 1 data Sum a b = First a | Second b deriving (Eq, Show) instance Functor (Sum a) where fmap f (First a) = First a fmap f (Second b) = Second (f b) -- 2 -- becuase the Left argument is a part of the Fucntor instance
{-# LANGUAGE FlexibleInstances #-} -- 16.17 Chapter exercises import GHC.Arr -- 1 data Bool = False | True -- no Functor instance -- 2 data BoolAndSomethingElse a = False' a | True' a instance Functor BoolAndSomethingElse where fmap f (False' a) = False' (f a) fmap f (True' a) = True' (f a) -- 3 data BoolAndMaybeSomethingElse a = Falsish | Truish a instance Functor BoolAndMaybeSomethingElse where fmap f (Truish a) = Truish (f a) -- 4 newtype Mu f = InF { outF :: f (Mu f) } -- I try to write implement a Functor instance for Mu but I failed. I -- think it cannot be a Functor instance because Mu has kind (* -> *) -- -> * but a Functor requires kind * -> * -- 5 data D = D (Array Word Word) Int Int -- It cannot be a Functor instance -- Rearrange the arguments to the type constructor of the datatype so -- the Functor instance works. -- 1 data Sum a b = First b | Second a instance Functor (Sum e) where fmap f (First a) = First (f a) fmap f (Second b) = Second b -- 2 data Company a b c = DeepBlue a b | Something c instance Functor (Company e e') where fmap f (Something b) = Something (f b) fmap _ (DeepBlue a c) = DeepBlue a c -- 3 data More a b = L b a b | R a b a deriving (Eq, Show) instance Functor (More x) where fmap f (L a b a') = L (f a) b (f a') fmap f (R b a b') = R b (f a) b'
{-# LANGUAGE FlexibleInstances #-} -- 16.17 Chapter exercises import GHC.Arr -- 1 data Bool = False | True -- no Functor instance -- 2 data BoolAndSomethingElse a = False' a | True' a instance Functor BoolAndSomethingElse where fmap f (False' a) = False' (f a) fmap f (True' a) = True' (f a) -- 3 data BoolAndMaybeSomethingElse a = Falsish | Truish a instance Functor BoolAndMaybeSomethingElse where fmap f (Truish a) = Truish (f a) -- 4 newtype Mu f = InF { outF :: f (Mu f) } -- I try to write implement a Functor instance for Mu but I failed. I -- think it cannot be a Functor instance because Mu has kind (* -> *) -- -> * but a Functor requires kind * -> * -- 5 data D = D (Array Word Word) Int Int -- It cannot be a Functor instance -- Rearrange the arguments to the type constructor of the datatype so -- the Functor instance works. -- 1 data Sum a b = First b | Second a instance Functor (Sum e) where fmap f (First a) = First (f a) fmap f (Second b) = Second b -- 2 data Company a b c = DeepBlue a b | Something c instance Functor (Company e e') where fmap f (Something b) = Something (f b) fmap _ (DeepBlue a c) = DeepBlue a c -- 3 data More a b = L b a b | R a b a deriving (Eq, Show) instance Functor (More x) where fmap f (L a b a') = L (f a) b (f a') fmap f (R b a b') = R b (f a) b' -- Write Functor instances for the following datatypes. -- 1 data Quant a b = Finance | Desk a | Bloor b instance Functor (Quant a) where fmap f Finance = Finance fmap f (Desk a) = Desk a fmap f (Bloor b) = Bloor (f b) -- 2 data K a b = K a instance Functor (K a) where fmap f (K a) = K a -- 3 newtype Flip f a b = Flip (f b a) deriving (Eq, Show) newtype K' a b = K' a instance Functor (Flip K' a) where fmap f (Flip (K' a)) = Flip $ K' (f a) -- 4 data EvilGoateeConst a b = GoatyConst b instance Functor (EvilGoateeConst a) where fmap f (GoatyConst a) = GoatyConst (f a) -- 5 data LiftItOut f a = LiftItOut (f a) instance Functor g => Functor (LiftItOut g) where fmap f (LiftItOut a) = LiftItOut (fmap f a) -- 6 data Parappa f g a = DaWrappa (f a) (g a) instance (Functor g, Functor h) => Functor (Parappa g h) where fmap f (DaWrappa g h) = DaWrappa (fmap f g) (fmap f h) -- 7 data IgnoreOne f g a b = IgnoringSomething (f a) (g b) instance Functor g => Functor (IgnoreOne f g a) where fmap f (IgnoringSomething x y) = IgnoringSomething x (fmap f y) -- 8 data Notorious g o a t = Notorious (g o) (g a) (g t) instance Functor g => Functor (Notorious g o a) where fmap f (Notorious x y z) = Notorious x y (fmap f z) -- 9 data List a'' = Nil | Cons a'' (List a'') instance Functor List where fmap f Nil = Nil fmap f (Cons a'' b'') = Cons (f a'') (fmap f b'') -- 10 data GoatLord a = NoGoat | OneGoat a | MoreGoats (GoatLord a) (GoatLord a) (GoatLord a) instance Functor GoatLord where fmap f NoGoat = NoGoat fmap f (OneGoat a) = OneGoat (f a) fmap f (MoreGoats x y z) = MoreGoats (fmap f x) (fmap f y) (fmap f z) -- 11 data TalkToMe a = Halt | Print String a | Read (String -> a) instance Functor TalkToMe where fmap _ Halt = Halt fmap f (Print str a) = Print str (f a) fmap f (Read s2a) = Read (f . s2a)
2.6. Chapter 17
-- 17.5 Applicative in use -- Exercises: Lookups import Data.List (elemIndex) -- 1 added :: Maybe Integer added = (+3) <$> (lookup 3 $ zip [1, 2, 3] [4, 5, 6]) -- 2 y :: Maybe Integer y = lookup 3 $ zip [1, 2, 3] [4, 5, 6] z :: Maybe Integer z = lookup 2 $ zip [1, 2, 3] [4, 5, 6] tupled :: Maybe (Integer, Integer) tupled = (,) <$> y <*> z -- 3 x' :: Maybe Int x' = elemIndex 3 [1..5] y' :: Maybe Int y' = elemIndex 4 [1..5] max' :: Int -> Int -> Int max' = max maxed :: Maybe Int maxed = max' <$> x' <*> y' -- 4 xs = [1..3] ys = [4..6] x'' :: Maybe Integer x'' = lookup 3 $ zip xs ys y'' :: Maybe Integer y'' = lookup 2 $ zip xs ys summed :: Maybe Integer summed = sum <$> ( (,) <$> x'' <*> y'' )
-- Exercise: Identity Instance newtype Identity a = Identity a deriving (Eq, Ord, Show) instance Functor Identity where fmap f (Identity a) = Identity (f a) instance Applicative Identity where pure a = Identity a (<*>) (Identity f) (Identity a) = Identity (f a)
-- Exercise: Constant Instance newtype Constant a b = Constant { getConstant :: a } deriving (Eq, Ord, Show) instance Functor (Constant a) where fmap f (Constant b) = Constant b instance Monoid a => Applicative (Constant a) where pure _ = Constant { getConstant = mempty } (<*>) (Constant x) (Constant y) = Constant (mappend x y)
-- Exercise: Fixer Upper import Data.Maybe main :: IO () main = do str1 <- return $ fromJust $ const <$> Just "Hello" <*> pure "World" str2 <- return $ fromJust $ (,,,) <$> Just 90 <*> Just 10 <*> Just "Timerness" <*> pure [1, 2, 3] print str1 print str2
-- List Applicative Exercise append :: List a -> List a -> List a append Nil ys = ys append (Cons x xs) ys = Cons x $ xs `append` ys fold :: (a -> b -> b) -> b -> List a -> b fold _ b Nil = b fold f b (Cons h t) = f h (fold f b t) concat' :: List (List a) -> List a concat' = fold append Nil data List a = Nil | Cons a (List a) deriving (Eq, Show) instance Functor List where fmap _ Nil = Nil fmap f (Cons x y) = Cons (f x) (fmap f y) instance Applicative List where pure x = Cons x Nil (<*>) _ Nil = Nil (<*>) Nil _ = Nil (<*>) (Cons f fs) xs = append (fmap f xs) (fs <*> xs) flatMap :: (a -> List b) -> List a -> List b flatMap f as = concat' $ fmap f as take' :: Int -> List a -> List a take' _ Nil = Nil take' 0 _ = Nil take' n (Cons x xs) = Cons x (take' (n-1) xs)
-- 17.9 Chapter Exercises -- 1 data Pair a = Pair a a deriving Show instance Functor Pair where fmap f (Pair x y) = Pair (f x) (f y) instance Applicative Pair where pure x = Pair x x (<*>) (Pair f g) (Pair a b) = Pair (f a) (g b) -- 2 data Two a b = Two a b instance Functor (Two a) where fmap f (Two x y) = Two x (f y) instance Monoid a => Applicative (Two a) where pure x = Two mempty x (<*>) (Two f g) (Two a b) = Two (mappend f a) (g b) -- 3 data Three a b c = Three a b c instance Functor (Three a b) where fmap f (Three x y z) = Three x y (f z) instance (Monoid a, Monoid b) => Applicative (Three a b) where pure x = Three mempty mempty x (<*>) (Three f g h) (Three x y z) = Three (mappend f x) (mappend g y) (h z) -- 4 data Three' a b = Three' a b b instance Functor (Three' a) where fmap f (Three' x y z) = Three' x (f y) (f z) instance Monoid a => Applicative (Three' a) where pure x = Three' mempty x x (<*>) (Three' f g h) (Three' x y z) = Three' (mappend f x) (g y) (h z) -- 5 data Four a b c d = Four a b c d instance Functor (Four a b c) where fmap f (Four x y z z') = Four x y z (f z') instance (Monoid a, Monoid b, Monoid c) => Applicative (Four a b c) where pure x = Four mempty mempty mempty x (<*>) (Four f g h h') (Four x y z z') = Four (mappend f x) (mappend g y) (mappend h z) (h' z') -- 6 data Four' a b = Four' a a a b instance Functor (Four' a) where fmap f (Four' x y z z') = Four' x y z (f z') instance Monoid a => Applicative (Four' a) where pure x = Four' mempty mempty mempty x (<*>) (Four' f g h h') (Four' x y z z') = Four' (mappend f x) (mappend g y) (mappend h z) (h' z')
-- Combinations import Control.Applicative (liftA3) stops :: String stops = "pbtdkg" vowels :: String vowels = "aeiou" combos :: [a] -> [b] -> [c] -> [(a, b, c)] combos x y z = liftA3 (,,) x y z main :: IO () main = do print . show $ combos stops vowels stops
2.7. Chapter 18
-- The answer is the exercise bind :: Monad m => (a -> m b) -> m a -> m b bind = flip (>>=)
-- Short Exercise: Either Monad data Sum a b = First a | Second b deriving (Eq, Show) instance Functor (Sum a) where fmap f (First x) = First x fmap f (Second x) = Second (f x) instance (Monoid a) => Applicative (Sum a) where pure x = Second x (<*>) (First x) _ = First x (<*>) _ (First x) = First x (<*>) (Second f) (Second x) = Second (f x) instance (Monoid a) => Monad (Sum a) where return = pure (>>=) (First x) _ = First x (>>=) (Second x) f = f x
-- 18.7 Chapter Exercises -- 1 data Nope a = NopeDotJpg instance Functor Nope where fmap _ _ = NopeDotJpg instance Applicative Nope where pure _ = NopeDotJpg (<*>) _ _ = NopeDotJpg instance Monad Nope where return = pure (>>=) NopeDotJpg _ = NopeDotJpg -- 2 data PhhhbbtttEither b a = Left' a | Right' b instance Functor (PhhhbbtttEither b) where fmap _ (Right' x) = Right' x fmap f (Left' x) = Left' (f x) instance (Monoid b) => Applicative (PhhhbbtttEither b) where pure x = Left' x (<*>) (Right' f) _ = Right' f (<*>) _ (Right' x) = Right' x (<*>) (Left' f) (Left' x) = Left' (f x) instance (Monoid b) => Monad (PhhhbbtttEither b) where return = pure (>>=) (Right' x) _ = Right' x (>>=) (Left' x) f = f x -- 3 newtype Identity a = Identity a deriving (Eq, Ord, Show) instance Functor Identity where fmap f (Identity x) = Identity (f x) instance Applicative Identity where pure x = Identity x (<*>) (Identity f) (Identity x) = Identity (f x) instance Monad Identity where return = pure (>>=) (Identity x) f = f x -- 4 data List a = Nil | Cons a (List a) append :: List a -> List a -> List a append Nil ys = ys append (Cons x xs) ys = Cons x $ xs `append` ys instance Functor List where fmap _ Nil = Nil fmap f (Cons x l) = Cons (f x) (fmap f l) instance Applicative List where pure x = Cons x Nil (<*>) Nil _ = Nil (<*>) _ Nil = Nil (<*>) (Cons f g) xs = fmap f xs `append` (g <*> xs) where append Nil ys = ys append (Cons x xs) ys = Cons x $ xs `append` ys instance Monad List where return = pure (>>=) Nil _ = Nil (>>=) (Cons x l) f = f x `append` (l >>= f)
-- 18.7 Chapter Exercises -- Write the following functions... import Control.Monad -- 1 j :: Monad m => m (m a) -> m a j x = x >>= id -- 2 l1 :: Monad m => (a -> b) -> m a -> m b l1 = fmap -- 3 l2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c l2 = liftM2 -- 4 a :: Monad m => m a -> m (a -> b) -> m b a = flip (<*>) -- 5 meh :: Monad m => [a] -> (a -> m b) -> m [b] meh [] _ = return [] meh (x:xs) f = (++) <$> (fmap (\x -> [x]) $ f x) <*> (meh xs f) -- 6 flipType :: (Monad m) => [m a] -> m [a] flipType xs = meh xs id
3. Sort
3.1. Quick Sort
def quick_sort(arr, first, last): if (first < last): wall = partition(arr, first, last) quick_sort(arr, first, wall - 1) quick_sort(arr, wall + 1, last) def partition(arr, first, last): # use last element as pivot wall = first for pos in range(first, last): if (arr[pos] < arr[last]): arr[pos], arr[wall] = arr[wall], arr[pos] wall += 1 arr[wall], arr[last] = arr[last], arr[wall] return wall a = [5, 1, 6, 2, 4] print(a) quick_sort(a, 0, len(a) - 1) print(a)
quicksort :: Ord a => [a] -> [a] quicksort [] = [] quicksort (x:xs) = quicksort small ++ (x : quicksort large) where small = [y | y <- xs, y <= x] large = [y | y <- xs, y > x] main :: IO () main = do let test = [5, 1, 6, 2, 4] :: [Int] putStrLn $ show test putStrLn $ show (quicksort test)
3.2. Bubble Sort
def bubble_sort(arr): swapped = True while swapped: swapped = False for i in range(0, len(arr) - 1): if arr[i] > arr[i + 1]: arr[i], arr[i + 1] = arr[i + 1], arr[i] swapped = True arr = [5, 1, 6, 2, 4] print(arr) bubble_sort(arr) print(arr)
4. Regression
4.1. Linear Regression
- Solution 1: Normal equation
- Solution 2: Batch gradient descent
import numpy as np import pandas as pd from numpy.linalg import inv data = pd.DataFrame({"square": [150, 200, 250, 300, 350, 400], "price": [6450, 7450, 8450, 9450, 15450, 18450]}) x = data["square"] x = np.row_stack((np.ones_like(x), x)) y = np.array(data["price"]) # Solution 1: normal equation theta = np.dot(y, np.dot(x.T, inv(np.dot(x, x.T)))) print("[S1]: Results: {}".format(theta)) # Solution 2: Batch gradient descent. theta = [-2400, 50] alpha = 0.00000000001 for i in range(100000): hypo = np.dot(theta, x) loss = hypo - y cost = np.sum(loss ** 2) / (2 * x.shape[1]) gradient = np.dot(loss, x.T) / x.shape[1] theta = theta - alpha * gradient print("[S2]: Results: {}".format(theta))
import numpy as np import pandas as pd from sklearn import linear_model data = pd.DataFrame({"square": [150, 200, 250, 300, 350, 400], "price": [6450, 7450, 8450, 9450, 15450, 18450]}) regr = linear_model.LinearRegression() regr.fit(data["square"].values.reshape(-1, 1), data["price"]) a, b = regr.coef_, regr.intercept_ print("Results: {}\t{}".format(b, a[0]))
5. Count words
{- Usage: - wc [wordname] [filename] -} import Control.Monad import Data.Char import System.Environment countWords :: String -> FilePath -> IO Int countWords w = liftM (length . filter (==w) . words . (map toLower)) . readFile main :: IO () main = do args <- getArgs wc <- countWords (args !! 0) (args !! 1) print wc