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
\begin{equation*} Y = \theta X \\ \theta = Y X^T (X X^T)^{-1} \end{equation*}
  • Solution 2: Batch gradient descent
\begin{equation*} J(\theta) = \frac{1}{2}\sum_{i=1}^m(h_{\theta}(x_i) - y_i)^2 \end{equation*} \begin{split} \frac{\partial J(\theta)}{\partial \theta_j} & = \frac{\partial}{\partial \theta_j}\frac{1}{2}(h_{\theta}(x) - y)^2 \\ & = 2 \cdot \frac{1}{2}(h_{\theta}(x) - y) \cdot \frac{\partial}{\partial \theta_j}(h_\theta(x) - y) \\ & = (h_\theta(x) - y) \cdot \frac{\partial}{\partial \theta_j}(\sum_{i=0}^n\theta_i x_i - y) \\ & = (h_\theta(x) - y)x_j \end{split}
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

Footnotes:

Edited by Isaac Gu on 2020-11-06 Fri 20:30