module Chapter9 where
import Data.Bool
import Data.Char
-- Exercise: enumFromTo
eft :: (Enum a) => a -> a -> [a]
eft start end = go start end []
where
go x y acc
| fromEnum (succ x) > (fromEnum y) = []
| otherwise = x : go (succ x) y acc
eftBool :: Bool -> Bool -> [Bool]
eftBool = eft
eftOrd :: Ordering -> Ordering -> [Ordering]
eftOrd = eft
eftInt :: Int -> Int -> [Int]
eftInt = eft
eftChar :: Char -> Char -> [Char]
eftChar = eft
-- Exercises: Thy Fearful Symmetry
-- 1.
myWords :: String -> [String]
myWords str = go str []
where
go x acc
| x == "" = acc
| otherwise =
takeWhile (/= ' ') x :
(go (dropWhile (== ' ') (dropWhile (/= ' ') x)) acc)
-- 2.
firstSen = "Tyger Tyger, burning bright\n"
secondSen = "In the forests of the night\n"
thirdSen = "What immortal hand or eye\n"
fourthSen =
"Could frame they fearful\
\ symmetry"
sentences = firstSen ++ secondSen ++ thirdSen ++ fourthSen
shouldEqual = lines sentences
splitString :: Char -> String -> [String]
splitString splitChar string = go splitChar string []
where
go x "" acc = acc
go x y acc =
go x (drop 1 . (dropWhile (/= x)) $ y) (acc ++ [takeWhile (/= x) y])
myLines :: String -> [String]
myLines = splitString '\n'
mainTigerTiger :: IO ()
mainTigerTiger =
print $ "Are they equal? " ++ show (myLines sentences == shouldEqual)
-- 3.
myWords' = splitString ' '
-- Exercises: Comprehend Thy Lists
mySqr = [x ^ 2 | x <- [1 .. 10]]
-- [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
comprehendA = [x | x <- mySqr, rem x 2 == 0]
comprehendB = [(x, y) | x <- mySqr, y <- mySqr, x < 50, y > 50]
comprehendC = take 5 [(x, y) | x <- mySqr, y <- mySqr, x < 50, y > 50]
guessA = [4, 16, 36, 64, 100]
guessB =
[ (1, 64)
, (1, 81)
, (1, 100)
, (4, 64)
, (4, 81)
, (4, 100)
, (9, 64)
, (9, 81)
, (9, 100)
, (16, 64)
, (16, 81)
, (16, 100)
, (25, 64)
, (25, 81)
, (25, 100)
, (36, 64)
, (36, 81)
, (36, 100)
, (49, 64)
, (49, 81)
, (49, 100)
]
guessC = [(1, 64), (1, 81), (1, 100), (4, 64), (4, 81)]
comprehended =
(comprehendA == guessA && comprehendB == guessB && comprehendC == guessC)
-- Exercises: Square Cube
squareCubeMySqr = [x ^ 2 | x <- [1 .. 5]]
squareCubeMyCube = [x ^ 3 | x <- [1 .. 5]]
-- 1a. zip squareCubeMySqr squareCubeMyCube
-- 1b. [(x ^ 2, x ^ 3) | x <- [1 .. 5]]
-- 2a. filter (\(x,y) -> x < 50 && y < 50) (zip squareCubeMySqr squareCubeMyCube)
-- 2b. [(x ^ 2, x ^ 3) | x <- [1 .. 5], x ^ 3 < 50]
-- 3. length [(x ^ 2, x ^ 3) | x <- [1 .. 5], x ^ 3 < 50]
-- Exercises: Bottom Madness
-- bottomMadness1 = [x ^ y | x <- [1, 2, 3, 4, 5], y <- [2, undefined]] -- blow up
--
-- bottomMadness2 = take 1 $ [x ^ y | x <- [1, 2, 3, 4, 5], y <- [2, undefined]] -- return 1
--
-- bottomMadness3 = sum [1, undefined, 3] -- blow up, has to evaluate all values
--
-- bottomMadness4 = length [1, 2, undefined] -- 3, it only recurses the spine
--
-- bottomMadness5 = length $ [1, 2, 3] ++ undefined -- blow up, it honly recurses the spine, however part of the spine itself is undefined
--
-- bottomMadness6 = take 1 $ filter even [1, 2, 3, undefined] -- [2] it lazily creates a constructor to create a list, but then it only takes the first element from the list constructor, so its ok.
--
-- bottomMadness7 take 1 $ filter even [1, 3, undefined] -- blow up, tries to read the values of the entire list because there are no even values in it, so it reaches undefined and blows up
--
-- bottomMadness8 take 1 $ filter odd [1, 3, undefined] -- [1], for the same reason as bottomMadness6
--
-- bottomMadness9 take 2 $ filter odd [1, 3, undefined] -- [1, 3], for the same reason as bottomMadness6
--
-- bottomMadness10 take 3 $ filter odd [1, 3, undefined] -- blow up, the first tow values are ok but it blows up on reaching the third value
-- Intermission: Is it in normal form?
-- 1. [1,2,3,4,5] NF
-- 2. 1 : 2 : 3 : 4 : _ WHNF (or neither?)
-- 3. enumFromTo 1 10 WHNF (or neither?)
-- 4. length [1, 2, 3, 4 5] WHNF
-- 5. sum (enumFromTo 1 10) neither
-- 6. neither
-- 7. NF
-- What does map exist for if fmap can do everything it does?
-- Exercises: More Bottoms
--------------------------
-- 1. take 1 $ map (+1) [undefined, 2, 3] - bottom.
-- 2. take 1 $ map (+1) [1, undefined, 3] - 2
-- 3. take 2 $ map (+1) [1, undefined, 3] - bottom
-- 4. Turns each character in a string into a Bool denoting whether the character was a vowel.
itIsMystery :: String -> [Bool]
itIsMystery xs = map (\x -> elem x "aeiou") xs
moreBottoms5a = map (^ 2) [1 .. 10] == [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
moreBottoms5b = map minimum [[1 .. 10], [10 .. 20], [20 .. 30]] == [1, 10, 20]
moreBottoms5c = map sum [[1 .. 5], [1 .. 5], [1 .. 5]] == [15, 15, 15]
moreBottoms6 =
map
(\x -> bool x (-x) (x == 3) --if x == 3
--then (-x)
--else (x)) -- [1..10][1,2,-3,4,5,6,7,8,9,10]
)
-- Exercises: Filtering
-----------------------
filtering1 x = mod x 3 == 0
filtering1Value = filter filtering1 [1 .. 30] == enumFromThenTo 3 6 30
filtering2 = length . filter filtering1
myFilter = filter (not . flip elem ["a", "an", "the"]) . words
-- Zipping exercises
--------------------
zip' :: [a] -> [b] -> [(a, b)]
zip' [] _ = []
zip' _ [] = []
zip' (x:xs) (y:ys) = (x, y) : (zip' xs ys)
-- Chapter Exercises
--------------------
-- Data.Char
------------
-- 1.
isUpper' :: Char -> Bool
isUpper' = undefined
toUpper' :: Char -> Char
toUpper' = undefined
-- 2. To write a function that filters all the uppercase letters out of a String, use isUpper
uppersOnly = filter isUpper
-- 3.
capitalize (x:xs) = toUpper x : xs
capitalize "" = ""
-- 4.
upperAll (x:xs) = toUpper x : (capitalize xs)
upperAll "" = ""
-- 5.
unsafeUpperFirst x = toUpper (head x)
-- 6.
unsafeUpperFirst' x = toUpper . head $ x
unsafeUpperFirst'' = toUpper . head
-- Ciphers
----------
-- See chapter-09-cipher.ha (module Chapter9Cipher)
-- Writing your own standard functions
--------------------------------------
and' :: [Bool] -> Bool
and' [] = True
and' (False:_) = False
and' (_:xs) = and' xs
-- 1.
or' :: [Bool] -> Bool
or' [] = False
or' (True:_) = True
or' (_:xs) = or' xs
-- 2.
any' :: (a -> Bool) -> [a] -> Bool
any' f [] = True
any' f xs = or' $ map f xs
-- 3.
elem' :: Eq a => a -> [a] -> Bool
elem' candidate [] = False
elem' candidate (x:xs)
| candidate == x = True
| otherwise = elem' candidate xs
-- 4.
reverse' :: [a] -> [a]
reverse' [] = []
reverse' (x:xs) = x : reverse' xs
-- 5.
squish :: [[a]] -> [a]
squish [] = []
squish (x:xs) = x ++ squish xs
-- 6.
squishMap :: (a -> [b]) -> [a] -> [b]
squishMap f [] = []
squishMap f (x:xs) = f x ++ squishMap f xs
squishMapWorks =
and'
[ squishMap (\x -> [1, x, 3]) [2] == [1, 2, 3]
, squishMap (\x -> "WO " ++ [x] ++ " HOO ") "123" ==
"WO 1 HOO WO 2 HOO WO 3 HOO "
]
-- 7.
squishAgain :: [[a]] -> [a]
squishAgain = squishMap id
-- 8.
maximumBy' :: (a -> a -> Ordering) -> [a] -> a
maximumBy' f [x] = x
maximumBy' f (x1:x2:[]) =
if f x1 x2 == GT
then x1
else x2
maximumBy' f (x1:x2:xs) =
maximumBy'
f
((if f x1 x2 == GT
then x1
else x2) :
xs)
-- 9.
minimumBy' :: (a -> a -> Ordering) -> [a] -> a
minimumBy' f [x] = x
minimumBy' f (x1:x2:[]) =
if f x1 x2 == LT
then x1
else x2
minimumBy' f (x1:x2:xs) =
minimumBy'
f
((if f x1 x2 == LT
then x1
else x2) :
xs)
-- 10
maximum' :: (Ord a) => [a] -> a
maximum' = maximumBy' compare
minimum' :: (Ord a) => [a] -> a
minimum' = minimumBy' compare