module Chapter8 where
import Data.List (intersperse)
incTimes :: (Eq a, Num a) => a -> a -> a
incTimes 0 n = n
incTimes times n = 1 + incTimes (times - 1) n
applyTimes :: (Eq a, Num a) => a -> (b -> b) -> b -> b
applyTimes 0 f b = b
applyTimes n f b = f (applyTimes (n - 1) f b)
incTimes' :: (Eq a, Num a) => a -> a -> a
incTimes' times n = applyTimes times (+ 1) n
applyTimes' :: (Eq a, Num a) => a -> (b -> b) -> b -> b
applyTimes' 0 f b = b
applyTimes' n f b = f . applyTimes (n - 1) f $ b
applyTimesExerciseA = applyTimes 5 (+ 1) 5
applyTimesExerciseB = (+ 1) (applyTimes 4 (+ 1) 5)
applyTimesExerciseC = (+ 1) ((+ 1) (applyTimes 3 (+ 1) 5))
applyTimesExerciseD = (+ 1) ((+ 1) ((+ 1) (applyTimes 2 (+ 1) 5)))
applyTimesExerciseE = (+ 1) ((+ 1) ((+ 1) ((+ 1) (applyTimes 1 (+ 1) 5))))
applyTimesExerciseF =
(+ 1) ((+ 1) ((+ 1) ((+ 1) ((+ 1) (applyTimes 0 (+ 1) 5)))))
applyTimesExerciseG = (+ 1) ((+ 1) ((+ 1) ((+ 1) ((+ 1) (5)))))
applyTimesExerciseH = (+ 1) ((+ 1) ((+ 1) ((+ 1) ((+ 1) 5))))
applyTimesExerciseI = (+ 1) ((+ 1) ((+ 1) ((+ 1) 6)))
applyTimesExerciseJ = (+ 1) ((+ 1) ((+ 1) 7))
applyTimesExerciseK = (+ 1) ((+ 1) 8)
applyTimesExerciseL = (+ 1) 9
applyTimesExerciseM = 10
checkApplyTimesExercise = foldl (\acc curr -> acc && curr == 10) True
applyTimesExerciseCorrect =
checkApplyTimesExercise
[ applyTimesExerciseA
, applyTimesExerciseB
, applyTimesExerciseC
, applyTimesExerciseD
, applyTimesExerciseE
, applyTimesExerciseF
, applyTimesExerciseG
, applyTimesExerciseH
, applyTimesExerciseI
, applyTimesExerciseJ
, applyTimesExerciseK
, applyTimesExerciseL
, applyTimesExerciseM
]
fibonacci :: Word -> Word
fibonacci 0 = 0
fibonacci 1 = 1
fibonacci n = fibonacci (n - 1) + fibonacci (n - 2)
divideStuff m n
| m - n <= n = (1, m - n)
| otherwise =
let result = (divideStuff (m - n) n)
in (1 + fst result, snd result)
dividedBy :: Integral a => a -> a -> (a, a)
dividedBy num denom = go num denom 0
where
go n d count
| n < d = (count, n)
| otherwise = go (n - d) d (count + 1)
-- Chapter Exercises
--------------------
-- Review of Types
------------------
-- 1. d) [[Bool]]
-- 2. b) [[3 == 3]], [6 > 5], [3 < 4]]
-- 3. d) all of the above
-- 4. b) func "Hello" "World"
--
-- Reviewing Currying
---------------------
cattyConny :: String -> String -> String
cattyConny x y = x ++ " mrow " ++ y
flippy :: String -> String -> String
flippy = flip cattyConny
appedCatty :: String -> String
appedCatty = cattyConny "woops"
frappe :: String -> String
frappe = flippy "haha"
-- 1. "woops mrow woohoo!"
-- 2. "1 mrow haha"
-- 3. "woops mrow 2 mrow haha"
-- 4. "woops mrow blue mrow haha"
-- 5. "pink mrow haha mrow green mrow woops mrow blue"
-- 6. "are mrow Pugs mrow awesome"
-- Recursion
------------
-- 1.
--dividedBy 15 2
-- go 15 2 0
-- otherwise = go (15 - 2) 2 (0 + 1)
-- go 13 2 1
-- otherwise = go (13 - 2) 2 (1 + 1)
-- go 11 2 2
-- otherwise = go (11 - 2) 2 (2 + 1)
-- go 9 2 3
-- otherwise = go (9 - 2) 2 (3 + 1)
-- go 7 2 4
-- otherwise = go (7 - 2) 2 (4 + 1)
-- go 5 2 5
-- otherwise = go (5 - 2) 2 (5 + 1)
-- go 3 2 6
-- otherwise = go (3 - 2) 2 (6 + 1)
-- go 1 2 7
-- 1 < 2 = (7, 1)
-- 2.
addThroughN :: (Eq a, Num a) => a -> a
addThroughN x = go x 0
where
go n count
| 1 == n = count + 1
| otherwise = go (n - 1) (count + n)
-- 3.
recursum :: (Integral a) => a -> a -> a
recursum x y = go x y 0
where
go stepBy stepsLeft total
| stepsLeft == 0 = total
| otherwise = go stepBy (stepsLeft - 1) (total + stepBy)
-- Fixing dividedBy
-- type DividedResult = Maybe (Integer, Integer)
fixedDividedBy :: Integral a => a -> a -> Maybe (a, a)
fixedDividedBy num denom =
if denom == 0 then Nothing else
go (abs num) (abs denom) 0
where
negativity = if num * denom < 0 then -1 else 1
go n d count
| n < d = Just (count * negativity , n)
| otherwise = go (n - d) d (count + 1)
-- McCarthy91 function
mcarthy91 :: (Integral a) => a -> a
mcarthy91 x
| x > 100 = x - 10
| otherwise = mcarthy91 . mcarthy91 $ (x + 11)
-- numbers into words
digitToWord :: Int -> String
digitToWord x
| x == 0 = "zero"
| x == 1 = "one"
| x == 2 = "two"
| x == 3 = "three"
| x == 4 = "four"
| x == 5 = "five"
| x == 6 = "six"
| x == 7 = "seven"
| x == 8 = "eight"
| x == 9 = "nine"
digits :: Int -> [Int]
digits x = go x []
where
go num acc =
let
(tens, remainder) = divMod num 10
result = remainder : acc
in
if tens == 0 then result
else go tens result
wordNumber :: Int -> String
wordNumber = concat . intersperse "-" . map digitToWord . digits