From f882643891500f51a879651146e2bd7fe3213135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Depreeuw?= Date: Sat, 21 Oct 2017 01:44:24 +0200 Subject: [PATCH] Complete chapters 5-9 --- 05-types/5.3-type-matching.md | 6 ++ 05-types/5.4-type-arguments.md | 11 +++ 05-types/5.5-parametricity.md | 7 ++ 05-types/5.6-apply-yourself.md | 6 ++ 05-types/5.8-chapter-excercises.md | 47 +++++++++++++ 05-types/src/arith3broken.hs | 10 +++ 05-types/src/defineFunc.hs | 42 ++++++++++++ 05-types/src/sing.hs | 22 ++++++ 05-types/src/typekwondo.hs | 52 ++++++++++++++ 06-typeclasses/6.14-chapter-exercises.md | 32 +++++++++ 06-typeclasses/6.6-eq-instances.md | 2 + 06-typeclasses/6.6-tuple-experiment.md | 3 + 06-typeclasses/6.8-will-they-work.md | 5 ++ 06-typeclasses/src/eqinstances.hs | 47 +++++++++++++ 06-typeclasses/src/typecheck.hs | 33 +++++++++ 06-typeclasses/src/typekwondo.hs | 13 ++++ .../7.11-chapter-exercises.md | 11 +++ 07-more-functional-patterns/7.3-grab-bag.md | 16 +++++ .../7.4-variety-pack.md | 9 +++ .../7.5-case-practise.md | 2 + .../7.6-artful-dodgy.md | 14 ++++ 07-more-functional-patterns/7.7-guard-duty.md | 24 +++++++ .../src/artfuldodgy.hs | 10 +++ .../src/casepractise.hs | 23 +++++++ 07-more-functional-patterns/src/writecode.hs | 43 ++++++++++++ 08-recursion/8.2-intermission.md | 15 +++++ 08-recursion/8.6-chapter-exercises.md | 40 +++++++++++ 08-recursion/src/dividedby.hs | 19 ++++++ 08-recursion/src/mccarthy91.hs | 6 ++ 08-recursion/src/recursion.hs | 38 +++++++++++ 08-recursion/src/wordnumber.hs | 25 +++++++ 09-lists/9.10-filtering.md | 2 + 09-lists/9.11-zipping-exercises.md | 2 + 09-lists/9.12-chapter-exercises.md | 9 +++ 09-lists/9.5-enumfromto.md | 2 + 09-lists/9.6-the-fearful-symmetry.md | 9 +++ 09-lists/9.7-comprehend-thy-lists.md | 4 ++ 09-lists/9.7-square-cube.md | 2 + 09-lists/9.8-bottom-madness.md | 21 ++++++ 09-lists/9.9-more-bottoms.md | 10 +++ 09-lists/src/char.hs | 25 +++++++ 09-lists/src/cipher.hs | 27 ++++++++ 09-lists/src/enumfromto.hs | 42 ++++++++++++ 09-lists/src/filtering.hs | 18 +++++ 09-lists/src/poemlines.hs | 21 ++++++ 09-lists/src/split.hs | 25 +++++++ 09-lists/src/squarecube.hs | 18 +++++ 09-lists/src/standards.hs | 67 +++++++++++++++++++ 09-lists/src/words.hs | 7 ++ 09-lists/src/zipping.hs | 14 ++++ 50 files changed, 958 insertions(+) create mode 100644 05-types/5.3-type-matching.md create mode 100644 05-types/5.4-type-arguments.md create mode 100644 05-types/5.5-parametricity.md create mode 100644 05-types/5.6-apply-yourself.md create mode 100644 05-types/5.8-chapter-excercises.md create mode 100644 05-types/src/arith3broken.hs create mode 100644 05-types/src/defineFunc.hs create mode 100644 05-types/src/sing.hs create mode 100644 05-types/src/typekwondo.hs create mode 100644 06-typeclasses/6.14-chapter-exercises.md create mode 100644 06-typeclasses/6.6-eq-instances.md create mode 100644 06-typeclasses/6.6-tuple-experiment.md create mode 100644 06-typeclasses/6.8-will-they-work.md create mode 100644 06-typeclasses/src/eqinstances.hs create mode 100644 06-typeclasses/src/typecheck.hs create mode 100644 06-typeclasses/src/typekwondo.hs create mode 100644 07-more-functional-patterns/7.11-chapter-exercises.md create mode 100644 07-more-functional-patterns/7.3-grab-bag.md create mode 100644 07-more-functional-patterns/7.4-variety-pack.md create mode 100644 07-more-functional-patterns/7.5-case-practise.md create mode 100644 07-more-functional-patterns/7.6-artful-dodgy.md create mode 100644 07-more-functional-patterns/7.7-guard-duty.md create mode 100644 07-more-functional-patterns/src/artfuldodgy.hs create mode 100644 07-more-functional-patterns/src/casepractise.hs create mode 100644 07-more-functional-patterns/src/writecode.hs create mode 100644 08-recursion/8.2-intermission.md create mode 100644 08-recursion/8.6-chapter-exercises.md create mode 100644 08-recursion/src/dividedby.hs create mode 100644 08-recursion/src/mccarthy91.hs create mode 100644 08-recursion/src/recursion.hs create mode 100644 08-recursion/src/wordnumber.hs create mode 100644 09-lists/9.10-filtering.md create mode 100644 09-lists/9.11-zipping-exercises.md create mode 100644 09-lists/9.12-chapter-exercises.md create mode 100644 09-lists/9.5-enumfromto.md create mode 100644 09-lists/9.6-the-fearful-symmetry.md create mode 100644 09-lists/9.7-comprehend-thy-lists.md create mode 100644 09-lists/9.7-square-cube.md create mode 100644 09-lists/9.8-bottom-madness.md create mode 100644 09-lists/9.9-more-bottoms.md create mode 100644 09-lists/src/char.hs create mode 100644 09-lists/src/cipher.hs create mode 100644 09-lists/src/enumfromto.hs create mode 100644 09-lists/src/filtering.hs create mode 100644 09-lists/src/poemlines.hs create mode 100644 09-lists/src/split.hs create mode 100644 09-lists/src/squarecube.hs create mode 100644 09-lists/src/standards.hs create mode 100644 09-lists/src/words.hs create mode 100644 09-lists/src/zipping.hs diff --git a/05-types/5.3-type-matching.md b/05-types/5.3-type-matching.md new file mode 100644 index 0000000..3a149a2 --- /dev/null +++ b/05-types/5.3-type-matching.md @@ -0,0 +1,6 @@ +# Exercises: Type Matching +1. (c) `not :: Bool -> Bool` +2. (d) `length :: [a] -> Int` +3. (b) `concat :: [[a]] -> [a]` +4. (a) `head :: [a] -> a` +5. (e) `(<) :: Ord a => a -> a -> Bool` diff --git a/05-types/5.4-type-arguments.md b/05-types/5.4-type-arguments.md new file mode 100644 index 0000000..613c59f --- /dev/null +++ b/05-types/5.4-type-arguments.md @@ -0,0 +1,11 @@ +# Exercises: Type Arguments + +1. (a) `Char -> Char -> Char` +2. (d) `Char` +3. (d) `Num b => b` +4. (c) `Double` +5. (a) `[Char]` +6. (e) `Eq b => b -> [Char]` +7. (d) `(Ord a, Num a) => a`, `a` is also of typeclass `Num` due to (`1 :: Num`) +8. (a) `(Ord a, Num a) => a` +9. (c) `Integer` \ No newline at end of file diff --git a/05-types/5.5-parametricity.md b/05-types/5.5-parametricity.md new file mode 100644 index 0000000..178b712 --- /dev/null +++ b/05-types/5.5-parametricity.md @@ -0,0 +1,7 @@ +# Exercises: Parametricity +1. As said this is impossible. A function which takes any type and returns that same type can't be anything else. As soon as you choose something else, you pose limitations on the type. E.g. `square x = x * x` requires that `x` can be applied to `(*)`, which means it has to be of type `Num` at least.\ +2. The only possibilies are to return either the first or the second argument. + 1. `fst' a1 a2 = a1` + 2. `snd' a1 a2 = a2` +3. Here there is only one possiblity: `snd'' a b = b`. + diff --git a/05-types/5.6-apply-yourself.md b/05-types/5.6-apply-yourself.md new file mode 100644 index 0000000..28d23ef --- /dev/null +++ b/05-types/5.6-apply-yourself.md @@ -0,0 +1,6 @@ +# Exercise: Apply Yourself +1. `myConcat :: [Char] -> [Char] -> [Char]`. The second argument to `(++)` is a `[Char]` and so all types need to be `[Char]`. +2. `myMult :: Fractional a => a -> a`. The `(/)` requires the `Fractional` typeclass (which is a subset of the `Num` class.) +3. `myTake :: Int -> [Char] -> [Char]`. Same reason a (1) +4. `myCom :: Int -> Bool`. Second argument of `(<)` is `Int`, which inherits the `Ord` typeclass so we no longer need to specify it. +5. `myAlph :: Char -> Bool`. \ No newline at end of file diff --git a/05-types/5.8-chapter-excercises.md b/05-types/5.8-chapter-excercises.md new file mode 100644 index 0000000..6364ddc --- /dev/null +++ b/05-types/5.8-chapter-excercises.md @@ -0,0 +1,47 @@ +# Chapter Excercises +## Multiple choice +1. (c) +2. (a) +3. (b) +4. (c) + +## Determine the type +1. + 1. `Num a => a` + 2. `Num a => (a, [Char])` + 3. `(Integer, [Char])` + 4. `Bool` + 5. `Int` + 6. `Bool` +2. `Num a => a` +3. `Num a => a -> a` +4. `Fractional a => a` +5. `[Char]` + +## Does it compile? +1. The definition of `wahoo` tries to apply a `Num` to another `Num` which does not work. Either change `bigNum` to take an argument (`bigNum x = (^) 5 $ x ; wahoo = bigNum $ 10`) or fix `wahoo`, e.g. `wahoo = bigNum` +2.Nothing wrong here. +3. `c` tries to apply `5` to `b = 5` which does not work. It's also expected to take an argument in the definition of `d = c 200`. A fix could thus be: `c = a 10`. +4. `c` is not defined for the definition of `b`. + +## Type variable or specific type constructor? +1. / +2. `zed` is fully polymorphic, `Zed` and `Blah` are concrete. +3. `a` is fully polymorphic, `b` is constrained and `C` is concrete. +4. `f` and `g` are fully polymorphic and `C` is concrete. + +## Write a type signature +1. `functionH :: [a] -> a` +2. `functionC :: (Ord a) => a -> a -> Bool` +3. `functionS :: (a, b) -> b` + +## Given a type, write the function +see src/defineFunc.hs + +## Fix it +1. see src/sing.hs +2. see src/sing.hs +3. see src/arith3broken.hs + +## Type-Kwon-Do +see src/typekwondo.hs \ No newline at end of file diff --git a/05-types/src/arith3broken.hs b/05-types/src/arith3broken.hs new file mode 100644 index 0000000..537f9a5 --- /dev/null +++ b/05-types/src/arith3broken.hs @@ -0,0 +1,10 @@ +module Arith3Broken where + +main :: IO () +-- Main should be main +main = do + print (1 + 2) -- added braces + putStrLn "10" -- must be String + print (negate (-1)) -- or negate 1 + print ((+) 0 blah) + where blah = negate 1 \ No newline at end of file diff --git a/05-types/src/defineFunc.hs b/05-types/src/defineFunc.hs new file mode 100644 index 0000000..3827c5b --- /dev/null +++ b/05-types/src/defineFunc.hs @@ -0,0 +1,42 @@ +module DefineFunc where + +-- 1 +i :: a -> a +i x = x; + +-- 2 +c :: a -> b -> a +c x _ = x + +-- 3 +c'' :: b -> a -> b +c'' x _ = x +-- Yes they are the same thing + +-- 4 +c' :: a -> b -> b +c' _ y = y + +-- 5 +r :: [a] -> [a] +--r (_:xs) = xs +r (x:xs) = xs ++ [x] +-- any many other options... + +-- 6 +co :: (b -> c) -> (a -> b) -> a -> c +co = (.) +-- co bToC aToB a = bToC (aToB a) +-- co f g a = (f . g) a +-- co f g = (f . g) +-- These are all the same. + +-- 7 +a :: (a -> c) -> a -> a +a _ x = x + +-- 8 +a' :: (a -> b) -> a -> b +a' = ($) +-- a f x = f x +-- a f = f \ No newline at end of file diff --git a/05-types/src/sing.hs b/05-types/src/sing.hs new file mode 100644 index 0000000..e76c80b --- /dev/null +++ b/05-types/src/sing.hs @@ -0,0 +1,22 @@ +module Sing where + +-- ++ should be -> +fstString :: [Char] -> [Char] +fstString x = x ++ " in the rain" + +-- Char should be [Char] +sndString :: [Char] -> [Char] +sndString x = x ++ " over the rainbow" + +-- added type signature +-- y should be 'Somewhere' +sing :: [Char] +sing = if (x > y) then fstString x else sndString y + where x = "Singin" + y = "Somewhere" + +-- 2 +singOther :: [Char] +singOther = if (x <= y) then fstString x else sndString y + where x = "Singin" + y = "Somewhere" \ No newline at end of file diff --git a/05-types/src/typekwondo.hs b/05-types/src/typekwondo.hs new file mode 100644 index 0000000..944bbcf --- /dev/null +++ b/05-types/src/typekwondo.hs @@ -0,0 +1,52 @@ +module TypeKwonDo where + +-- 1 +f :: Int -> String +f = undefined + +g :: String -> Char +g = undefined + +h :: Int -> Char +h = g . f + +-- 2 +data A +data B +data C + +q :: A -> B +q = undefined + +w :: B -> C +w = undefined + +e :: A -> C +e = w . q + +-- 3 +data X +data Y +data Z + +xz :: X -> Z +xz = undefined + +yz :: Y -> Z +yz = undefined + +xform :: (X, Y) -> (Z, Z) +xform (x, y) = (xz x, yz y) + +-- 4 +munge :: (x -> y) + -> (y -> (w, z)) + -> x + -> w +munge f1 f2 = fst . f2 . f1 +--munge f1 f2 x = fst $ (f2 . f1) x +-- (f2 . f1) :: x -> (w,z) +-- munge f1 f2 = fst $ (f2 . f1) +-- doesn't work because you apply fst to a function and it +-- expects a tuple. (f2 . f1) needs to be applied to an argument to get the +-- tuple on which fst can operate. \ No newline at end of file diff --git a/06-typeclasses/6.14-chapter-exercises.md b/06-typeclasses/6.14-chapter-exercises.md new file mode 100644 index 0000000..782462a --- /dev/null +++ b/06-typeclasses/6.14-chapter-exercises.md @@ -0,0 +1,32 @@ +# Chapter Excercises +## Multiple choice +1. (c) +2. (b) +3. (a) +4. (c) +5. (a) + +## Does it typecheck? +see src/typecheck.hs + +## Given a datatype declaration, what can we do? +1. Will not type check. `"chases"` is a `String` not a `Rocks` and `True` is of type `Bool`, not `Yeah` +2. Will typecheck. +3. Will typecheck. +4. Will not typecheck, because `Papu` is not an instance of `Ord` + +## Match the types +1. Can't be substituted +2. Can't be substituted +3. Can be substituted +4. Can be substituted +5. Can be substituted +6. Can be substituted +7. Can't be substituted +8. Can't be substituted +9. Can be substituted +10. Can be substituted +11. Can't be substituted + +## Type-Kwon-Do Two: Electric Typealoo +see src/typekwondo.hs \ No newline at end of file diff --git a/06-typeclasses/6.6-eq-instances.md b/06-typeclasses/6.6-eq-instances.md new file mode 100644 index 0000000..98c0e95 --- /dev/null +++ b/06-typeclasses/6.6-eq-instances.md @@ -0,0 +1,2 @@ +# Exercises: Eq Instances +see src/eqinstances.hs \ No newline at end of file diff --git a/06-typeclasses/6.6-tuple-experiment.md b/06-typeclasses/6.6-tuple-experiment.md new file mode 100644 index 0000000..db34b60 --- /dev/null +++ b/06-typeclasses/6.6-tuple-experiment.md @@ -0,0 +1,3 @@ +# Exercises: Tuple Experiment +`quotRem` and `divMod` return a tuple contain both the results of `(quot, rem)` and `(div, mod)` respectively. E.g. `quotRem 3 5` would return `(0, 3)` + diff --git a/06-typeclasses/6.8-will-they-work.md b/06-typeclasses/6.8-will-they-work.md new file mode 100644 index 0000000..fc3d8de --- /dev/null +++ b/06-typeclasses/6.8-will-they-work.md @@ -0,0 +1,5 @@ +# Exercises: Will They Work? +1. This will work. It will return `5 :: Int` +2. This will also work. It will return `LT` +3. This won't work as the arguments are different types. +4. This will work and will return `False` \ No newline at end of file diff --git a/06-typeclasses/src/eqinstances.hs b/06-typeclasses/src/eqinstances.hs new file mode 100644 index 0000000..4b6b528 --- /dev/null +++ b/06-typeclasses/src/eqinstances.hs @@ -0,0 +1,47 @@ +module EqInstances where + +-- 1 +data TisAnInteger = TisAn Integer +instance Eq TisAnInteger where + TisAn x == TisAn y = x == y + +-- 2 +data TwoIntegers = Two Integer Integer +instance Eq TwoIntegers where + Two x1 x2 == Two y1 y2 = + (x1 == y1) && (x2 == y2) + +-- 3 +data StringOrInt = + TisAnInt Int + | TisAString String +instance Eq StringOrInt where + TisAnInt x == TisAnInt y = x == y + TisAString s1 == TisAString s2 = s1 == s2 + _ == _ = False + +-- 4 +data Pair a = Pair a a +instance Eq a => Eq (Pair a) where + (==) (Pair a1 a2) (Pair b1 b2) = + (a1 == b1) && (a2 == b2) + +-- 5 +data Tuple a b = Tuple a b +instance (Eq a, Eq b) => Eq (Tuple a b) where + (==) (Tuple a1 b1) (Tuple a2 b2) = + (a1 == a2) && (b1 == b2) + +-- 6 +data Which a = ThisOne a | ThatOne a +instance Eq a => Eq (Which a) where + (==) (ThisOne a) (ThisOne a') = a == a' + (==) (ThatOne a) (ThatOne a') = a == a' + (==) _ _ = False + +-- 7 +data EitherOr a b = Hello a | Goodbye b +instance (Eq a, Eq b) => Eq (EitherOr a b) where + (==) (Hello a) (Hello a') = a == a' + (==) (Goodbye b) (Goodbye b') = b == b' + (==) _ _ = False diff --git a/06-typeclasses/src/typecheck.hs b/06-typeclasses/src/typecheck.hs new file mode 100644 index 0000000..917c866 --- /dev/null +++ b/06-typeclasses/src/typecheck.hs @@ -0,0 +1,33 @@ +module TypeCheck where + +-- Does it Type Check ? + +-- 1 Does not typecheck. Add `deriving Show` +data Person = Person Bool deriving Show + +printPerson :: Person -> IO () +printPerson person = putStrLn (show person) + +-- 2 Does not typecheck. Add `deriving Eq` +data Mood = Blah | Woot deriving (Show, Eq) + +settleDown :: Mood -> Mood +settleDown x = if x == Woot then Blah else x + +-- 3 +-- a. Mood values +-- b. Doesn't typecheck as it expects a `Mood` but gets a `Num` +-- c. Won't compile as Mood is not an instance of Ord + +-- 4 This typecheckes. +type Subject = String +type Verb = String +type Object = String + +data Sentence = Sentence Subject Verb Object deriving (Show, Eq) + +s1 :: Object -> Sentence +s1 = Sentence "dogs" "drool" +s2 :: Sentence +s2 = Sentence "Julie" "loves" "dogs" + diff --git a/06-typeclasses/src/typekwondo.hs b/06-typeclasses/src/typekwondo.hs new file mode 100644 index 0000000..10417a8 --- /dev/null +++ b/06-typeclasses/src/typekwondo.hs @@ -0,0 +1,13 @@ +module TypeKwonDo where + +-- 1 +chk :: Eq b => (a -> b) -> a -> b -> Bool +chk f a = (==) (f a) + +-- 2 +arith :: Num b + => (a -> b) + -> Integer + -> a + -> b +arith f i a = (f a) + (fromInteger i) \ No newline at end of file diff --git a/07-more-functional-patterns/7.11-chapter-exercises.md b/07-more-functional-patterns/7.11-chapter-exercises.md new file mode 100644 index 0000000..3ceb973 --- /dev/null +++ b/07-more-functional-patterns/7.11-chapter-exercises.md @@ -0,0 +1,11 @@ +# Chapter Exercises +## Multiple Choice +1. (d) +2. (b) +3. (d) +4. (b) +5. (a) + +## Let's write code +see src/writecode.hs + diff --git a/07-more-functional-patterns/7.3-grab-bag.md b/07-more-functional-patterns/7.3-grab-bag.md new file mode 100644 index 0000000..25803da --- /dev/null +++ b/07-more-functional-patterns/7.3-grab-bag.md @@ -0,0 +1,16 @@ +# Exercises: Grab Bag +## Exercise 1 +They are all equivalent. + +## Exercise 2 +(d) + +## Exercise 3 +### addOneIfOdd +`f = \n -> n + 1` + +### addFive +`addFive = \x -> \y -> (if (x > y) then y else x) + 5` + +### mflip +`mflip f x y = f y x` \ No newline at end of file diff --git a/07-more-functional-patterns/7.4-variety-pack.md b/07-more-functional-patterns/7.4-variety-pack.md new file mode 100644 index 0000000..5829f3c --- /dev/null +++ b/07-more-functional-patterns/7.4-variety-pack.md @@ -0,0 +1,9 @@ +# Exercises: Variety Pack +## Exercise 1 +1. The type of k is `(a,b) -> a` +2. The type of k2 is `[Char]` It is different from k1 and k3. +3. k3 + +## Exercise 2 +`f (a,_,c) (d,_,f) = ((a,d), (c,f))` + diff --git a/07-more-functional-patterns/7.5-case-practise.md b/07-more-functional-patterns/7.5-case-practise.md new file mode 100644 index 0000000..90d56e5 --- /dev/null +++ b/07-more-functional-patterns/7.5-case-practise.md @@ -0,0 +1,2 @@ +#Exercises: Case Practise +see src/casepractise.hs \ No newline at end of file diff --git a/07-more-functional-patterns/7.6-artful-dodgy.md b/07-more-functional-patterns/7.6-artful-dodgy.md new file mode 100644 index 0000000..bee6ec8 --- /dev/null +++ b/07-more-functional-patterns/7.6-artful-dodgy.md @@ -0,0 +1,14 @@ +# Exercise: Artful Dodgy +see src/artfuldodgy.hs + +1. 1 +2. 11 +3. 22 +4. 21 +5. 12 +6. 11 +7. 21 +8. 21 +9. 22 +10. 31 +11. 23 \ No newline at end of file diff --git a/07-more-functional-patterns/7.7-guard-duty.md b/07-more-functional-patterns/7.7-guard-duty.md new file mode 100644 index 0000000..664b6ef --- /dev/null +++ b/07-more-functional-patterns/7.7-guard-duty.md @@ -0,0 +1,24 @@ +# Exercises: Guard Duty +## Exercise 1 +If you start with the `otherwise` statement, all grades will be F's. + +## Exercise 2 +It will still work, but the result won't be as expected. E.g. if you move `| y >= 0.9 = 'A'` below the B grade, then any grade of 80 or higher will be a B, because `0.9 >= 0.8` is true and thus it matches with the grade for B. + +## Exercise 3 +(b) + +## Exercise 4 +`[a]` + +## Exercise 5 +`pal :: [a] -> Bool` + +## Exercise 6 +(c) + +## Exercise 7 +`Ord a => a` + +## Exercise 8 +`numbers :: (Ord a, Num a, Num b) => a -> b` \ No newline at end of file diff --git a/07-more-functional-patterns/src/artfuldodgy.hs b/07-more-functional-patterns/src/artfuldodgy.hs new file mode 100644 index 0000000..a2e5fb7 --- /dev/null +++ b/07-more-functional-patterns/src/artfuldodgy.hs @@ -0,0 +1,10 @@ +module ArtfulDodgy where + +dodgy :: Num a => a -> a -> a +dodgy x y = x + y * 10 + +oneIsOne :: Num a => a -> a +oneIsOne = dodgy 1 + +oneIsTwo :: Num a => a -> a +oneIsTwo = (flip dodgy) 2 \ No newline at end of file diff --git a/07-more-functional-patterns/src/casepractise.hs b/07-more-functional-patterns/src/casepractise.hs new file mode 100644 index 0000000..8ac199a --- /dev/null +++ b/07-more-functional-patterns/src/casepractise.hs @@ -0,0 +1,23 @@ +module CasePractise where + +-- 1 +functionC :: Ord a => a -> a -> a +functionC x y = + case (x > y) of + True -> x + False -> y + +-- 2 +ifEvenAdd2 :: Integral a => a -> a +ifEvenAdd2 n = + case even n of + True -> n + 2 + False -> n + +-- 3 +nums :: (Ord a, Num a) => a -> a +nums x = + case compare x 0 of + LT -> -1 + GT -> 1 + EQ -> 0 \ No newline at end of file diff --git a/07-more-functional-patterns/src/writecode.hs b/07-more-functional-patterns/src/writecode.hs new file mode 100644 index 0000000..c35eaa2 --- /dev/null +++ b/07-more-functional-patterns/src/writecode.hs @@ -0,0 +1,43 @@ +module WriteCode where + +-- 1a +tensDigit :: Integral a => a -> a +tensDigit = snd . (flip divMod) 10 +-- 1b This has the same type. +-- 1c +hunsD :: Integral a => a -> a +hunsD = snd . (flip divMod) 100 + +-- 2 +foldBool1 :: a -> a -> Bool -> a +foldBool1 x y b = + case b of + False -> x + True -> y + +foldBool2 :: a -> a -> Bool -> a +foldBool2 x y b + | b == False = x + | otherwise = y + +-- 3 +g :: (a -> b) -> (a, c) -> (b, c) +g f (a, c) = (f a, c) + +-- 4 +roundTrip :: (Show a, Read a) => a -> a +roundTrip a = read (show a) + +main :: IO () +main = do + print ((roundTrip 4) :: Integer) + print (id 4 :: Integer) + +-- 5 +roundTrip' :: (Show a, Read a) => a -> a +roundTrip' = read . show + +-- 6 +roundTrip'' :: (Show a, Read b) => a -> b +roundTrip'' = read . show +-- roundTrip'' 4 :: Integer \ No newline at end of file diff --git a/08-recursion/8.2-intermission.md b/08-recursion/8.2-intermission.md new file mode 100644 index 0000000..afbc345 --- /dev/null +++ b/08-recursion/8.2-intermission.md @@ -0,0 +1,15 @@ +# Intermission: Exercise +``` +applyTimes 5 (+1) 5 + = (+1) (applyTimes 4 (+1) 5) + = (+1) ((+1) (applyTimes 3 (+1) 5)) + = (+1) ((+1) ((+1) (applyTimes 2 (+1) 5))) + = (+1) ((+1) ((+1) ((+1) (applyTimes 1 (+1) 5)))) + = (+1) ((+1) ((+1) ((+1) ((+1) (applyTimes 0 (+1) 5))))) + = (+1) ((+1) ((+1) ((+1) ((+1) (5))))) + = (+1) ((+1) ((+1) ((+1) (6)))) + = (+1) ((+1) ((+1) (7))) + = (+1) ((+1) (8)) + = (+1) (9) + = 10 +``` \ No newline at end of file diff --git a/08-recursion/8.6-chapter-exercises.md b/08-recursion/8.6-chapter-exercises.md new file mode 100644 index 0000000..69b19ff --- /dev/null +++ b/08-recursion/8.6-chapter-exercises.md @@ -0,0 +1,40 @@ +# Chapter Exercises +## Review of types +1. `[[Bool]]` +2. (c) +3. (d) +4. (b) + +## Reviewing currying +1. `"woops mrow wooho!"` +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 +### Exercise 1 +``` +dividedBy 15 2 + = go 15 2 0 + = go 13 2 1 + = go 11 2 2 + = go 9 2 3 + = go 7 2 4 + = go 5 2 5 + = go 3 2 6 + = go 1 2 7 + = (7,1) +``` +### Exercise 2 & 3 +see src/recursion.hs + +### Exercise 4 +see src/dividedby.hs + +### Exercise 5 +see src/mccarthy91.hs + +## Numbers into words +see src/wordnumber.hs \ No newline at end of file diff --git a/08-recursion/src/dividedby.hs b/08-recursion/src/dividedby.hs new file mode 100644 index 0000000..b3b4a1e --- /dev/null +++ b/08-recursion/src/dividedby.hs @@ -0,0 +1,19 @@ +module DividedBy where + +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) + +-- For this exercise, we'll revert to the Integer -> Integer -> Integer type. +-- This, to be able to use the hint provides which uses Integer +data DividedResult = + Result Integer + | DividedByZero + deriving (Show) + +dividedBy' :: Integer -> Integer -> DividedResult +dividedBy' _ 0 = DividedByZero +dividedBy' num denom = -- is actually the same as the regular function. + Result . toInteger . fst $ dividedBy num denom \ No newline at end of file diff --git a/08-recursion/src/mccarthy91.hs b/08-recursion/src/mccarthy91.hs new file mode 100644 index 0000000..0fc4d76 --- /dev/null +++ b/08-recursion/src/mccarthy91.hs @@ -0,0 +1,6 @@ +module McCarthy91 where + +mc91 :: (Integral a) => a -> a +mc91 n + | n > 100 = n - 10 + | otherwise = mc91 . mc91 $ n + 11 \ No newline at end of file diff --git a/08-recursion/src/recursion.hs b/08-recursion/src/recursion.hs new file mode 100644 index 0000000..c05052c --- /dev/null +++ b/08-recursion/src/recursion.hs @@ -0,0 +1,38 @@ +module Recursion where + +-- 2 +recsum :: (Eq a, Num a) => a -> a +recsum 1 = 1 +recsum n = n + (recsum (n -1)) +-- The above function does not really work with negative numbers but we can't +-- check for negativity because this would require the Ord typeclass. +-- You can use abs however +recsum' :: (Eq a, Num a) => a -> Maybe a +recsum' n + | isNegative n = Nothing + | n == 0 = Just 0 + | otherwise = go (+n) (recsum' (n - 1)) + where go f (Just a) = Just (f a) + go _ _ = Nothing +-- Or: | otherwise = fmap (+n) (recsum' (n - 1)) + + +-- 3 +myMult :: (Integral a) => a -> a -> a +myMult 0 _ = 0 +myMult _ 0 = 0 +myMult x y + | y >= 0 = go x y + -- if y is negative we'll just treat y as positive and negate the result. + -- x * (-y) = - (x * y) + | otherwise = negate $ go x $ negate y + where go a 1 = a + go a b = a + (go a (b-1)) + +-- helper functions +isPositive :: (Eq a, Num a) => a -> Bool +isPositive n = + n == abs n + +isNegative :: (Eq a, Num a) => a -> Bool +isNegative = not . isPositive \ No newline at end of file diff --git a/08-recursion/src/wordnumber.hs b/08-recursion/src/wordnumber.hs new file mode 100644 index 0000000..4566cd4 --- /dev/null +++ b/08-recursion/src/wordnumber.hs @@ -0,0 +1,25 @@ +module WordNumber where + +import Data.List (intersperse) + +digitToWord :: Int -> String +digitToWord 0 = "zero" +digitToWord 1 = "one" +digitToWord 2 = "two" +digitToWord 3 = "three" +digitToWord 4 = "four" +digitToWord 5 = "five" +digitToWord 6 = "six" +digitToWord 7 = "seven" +digitToWord 8 = "eight" +digitToWord 9 = "nine" +digitToWord _ = "" + +digits :: Int -> [Int] +digits n + | d == 0 = [r] + | otherwise = digits d ++ [r] + where (d,r) = divMod (abs n) 10 + +wordNumber :: Int -> String +wordNumber = concat . intersperse "-" . map digitToWord . digits \ No newline at end of file diff --git a/09-lists/9.10-filtering.md b/09-lists/9.10-filtering.md new file mode 100644 index 0000000..d6e23e6 --- /dev/null +++ b/09-lists/9.10-filtering.md @@ -0,0 +1,2 @@ +# Exercises: Filtering +see src/filtering.hs \ No newline at end of file diff --git a/09-lists/9.11-zipping-exercises.md b/09-lists/9.11-zipping-exercises.md new file mode 100644 index 0000000..12bac05 --- /dev/null +++ b/09-lists/9.11-zipping-exercises.md @@ -0,0 +1,2 @@ +# Zipping Exercises +see src/zipping.hs \ No newline at end of file diff --git a/09-lists/9.12-chapter-exercises.md b/09-lists/9.12-chapter-exercises.md new file mode 100644 index 0000000..a448003 --- /dev/null +++ b/09-lists/9.12-chapter-exercises.md @@ -0,0 +1,9 @@ +# Chapter Exercises +## Data.Char +see src/char.hs + +## Ciphers +see src/cipher.hs + +## Writing your own standard functions +see src/standards.hs \ No newline at end of file diff --git a/09-lists/9.5-enumfromto.md b/09-lists/9.5-enumfromto.md new file mode 100644 index 0000000..49ed77f --- /dev/null +++ b/09-lists/9.5-enumfromto.md @@ -0,0 +1,2 @@ +# Exercise: EnumFromTo +see src/enumfromto.hs \ No newline at end of file diff --git a/09-lists/9.6-the-fearful-symmetry.md b/09-lists/9.6-the-fearful-symmetry.md new file mode 100644 index 0000000..94772ac --- /dev/null +++ b/09-lists/9.6-the-fearful-symmetry.md @@ -0,0 +1,9 @@ +# Exercises: The Fearful Symmetry +## Exercise 1 +see src/words.hs + +## Exercise 2 +see src/poemlines.hs + +## Exercise 3 +see src/split.hs \ No newline at end of file diff --git a/09-lists/9.7-comprehend-thy-lists.md b/09-lists/9.7-comprehend-thy-lists.md new file mode 100644 index 0000000..d6c40d9 --- /dev/null +++ b/09-lists/9.7-comprehend-thy-lists.md @@ -0,0 +1,4 @@ +# Exercises: Comprehend Thy Lists +1. Takes all squares of the even numbers from 1 to 10 +2. Combines all pairs of squares from numbers 1 to 10 smaller than 50 and larger than 50. +3. Takes the first 5 items of the previous list. The pairs will first be generated while keeping the x's the same. I.e. `[(1,64),(1,81),(1,100),(4,64),(4,81)]` \ No newline at end of file diff --git a/09-lists/9.7-square-cube.md b/09-lists/9.7-square-cube.md new file mode 100644 index 0000000..8995c9e --- /dev/null +++ b/09-lists/9.7-square-cube.md @@ -0,0 +1,2 @@ +# Exercises: Square Cube +see src/squarecube.hs \ No newline at end of file diff --git a/09-lists/9.8-bottom-madness.md b/09-lists/9.8-bottom-madness.md new file mode 100644 index 0000000..034921d --- /dev/null +++ b/09-lists/9.8-bottom-madness.md @@ -0,0 +1,21 @@ +# Exercises: Bottom Madness +## Will it blow up? +1. Bottom +2. Will return `[1]` +3. Bottom +4. Will return `3` +5. Bottom +6. Will return `[2]` +7. Bottom +8. Will return `[1]` +9. Will return `[1,3]` +10. Bottom + +## Intermission: Is it in normal form? +1. NF - No further evaluation possible. +2. WHNF - `:` is a data constructor, but due to the `_` it isn't fully evaluated. +3. Neither - `enumFromTo` is not a data constructor +4. Neither - `length` is not a data constructor +5. Neither - `sum` is not a data constructor +6. Neither - `++` is not a data constructor +7. WHNF - `(,)` is a data constructor, but due to the `_` it is not fully evaluated. \ No newline at end of file diff --git a/09-lists/9.9-more-bottoms.md b/09-lists/9.9-more-bottoms.md new file mode 100644 index 0000000..b135a82 --- /dev/null +++ b/09-lists/9.9-more-bottoms.md @@ -0,0 +1,10 @@ +# Exercises: More Bottoms +1. Bottom +2. Will return `2` +3. Bottom +4. `itIsMyster :: [Char] -> [Bool]` replaces every character in the input to `True` if it is a vowel and `False` otherwise. +5. The answers: + 1. Squares every value in the list: `[1,4,9,16,26,36,49,64,81,100]` + 2. Takes the smallest element of every sub-list: `[1,10,20]` + 3. Sums every sub-list: `[15,15,15]` + 4. `map (\x -> bool (x) (-x) (x == 3))` \ No newline at end of file diff --git a/09-lists/src/char.hs b/09-lists/src/char.hs new file mode 100644 index 0000000..d093eb1 --- /dev/null +++ b/09-lists/src/char.hs @@ -0,0 +1,25 @@ +module Char where + + import Data.Char + + -- 2 + filterUpper :: [Char] -> [Char] + filterUpper = filter isUpper + + -- 3 + upFirst :: [Char] -> [Char] + upFirst [] = [] + upFirst (x:xs) = toUpper x : xs + + -- 4 + upAll :: [Char] -> [Char] + upAll [] = [] + upAll (x:xs) = toUpper x : upAll xs + + -- 5 + getUppedFirst :: String -> Char + getUppedFirst s = toUpper $ head s + + -- 6 + getUppedFirst' :: String -> Char + getUppedFirst' = toUpper . head \ No newline at end of file diff --git a/09-lists/src/cipher.hs b/09-lists/src/cipher.hs new file mode 100644 index 0000000..af3d95f --- /dev/null +++ b/09-lists/src/cipher.hs @@ -0,0 +1,27 @@ +module Cipher where + + import Data.Char + + -- Chapter 9.12 + caesar :: String -> Int -> String + caesar [] _ = [] + caesar (x:xs) k + | isAlpha x = go x k ++ caesar xs k + | otherwise = caesar xs k + where go c key = [enc c (+) key] + + unCaesar :: String -> Int -> String + unCaesar [] _ = [] + unCaesar (x:xs) k + | isAlpha x = go x k ++ unCaesar xs k + | otherwise = caesar xs k + where go c key = [enc c (-) key] + + enc :: Char -> (Int -> Int -> Int) -> Int -> Char + enc c f k + | isAlpha c = chr i + | otherwise = c + where i = (mod ci r) + (ord base) + ci = f ((ord c) - (ord base)) k + r = 26 + base = 'a' \ No newline at end of file diff --git a/09-lists/src/enumfromto.hs b/09-lists/src/enumfromto.hs new file mode 100644 index 0000000..3aaa57a --- /dev/null +++ b/09-lists/src/enumfromto.hs @@ -0,0 +1,42 @@ +module EnumFromTo where + +eftBool :: Bool -> Bool -> [Bool] +-- eftBool False True = [False, True] +-- eftBool False False = [False] +-- eftBool True False = [] +-- eftBool True True = [True] +-- eftBool a b +-- | a > b = [] +-- | a == b = [a] +-- | otherwise = [a] ++ (eftBool (succ a) b) +eftBool = helper + + +eftOrd :: Ordering -> Ordering -> [Ordering] +-- eftOrd a b +-- | a > b = [] +-- | a == b = [a] +-- | otherwise = [a] ++ (eftOrd (succ a) b) +eftOrd = helper + +eftInt :: Int -> Int -> [Int] +-- eftInt a b +-- | a > b = [] +-- | a == b = [a] +-- | otherwise = [a] ++ (eftInt (succ a) b) +eftInt = helper + +eftChar :: Char -> Char -> [Char] +-- eftChar a b +-- | a > b = [] +-- | a == b = [a] +-- | otherwise = [a] ++ (eftChar (succ a) b) +eftChar = helper + +helper :: Enum a => a -> a -> [a] +helper a b + | ai > bi = [] + | ai == bi = [a] + | otherwise = [a] ++ (helper (succ a) b) + where ai = fromEnum a + bi = fromEnum b \ No newline at end of file diff --git a/09-lists/src/filtering.hs b/09-lists/src/filtering.hs new file mode 100644 index 0000000..ffa1cc7 --- /dev/null +++ b/09-lists/src/filtering.hs @@ -0,0 +1,18 @@ +module Filtering where + + myFilter :: Integral a => [a] -> [a] + myFilter = filter (\x -> rem x 3 == 0) + + myFilterLength :: Integral a => [a] -> Int + myFilterLength = length . myFilter + + myFilter' :: [Char] -> [[Char]] + myFilter' = filter + (\x -> case x of + "the" -> False + "a" -> False + "an" -> False + _ -> True + ) + . words + diff --git a/09-lists/src/poemlines.hs b/09-lists/src/poemlines.hs new file mode 100644 index 0000000..2cba8e3 --- /dev/null +++ b/09-lists/src/poemlines.hs @@ -0,0 +1,21 @@ +module PoemLines where + +firstSen :: [Char] +firstSen = "Tyger Tyger, burning bright\n" +secondSen :: [Char] +secondSen = "In the forests of the night\n" +thirdSen :: [Char] +thirdSen = "What immortal hand or eye\n" +fourthSen :: [Char] +fourthSen = "Could frame thy fearful\ + \ symmetry?" + +sentences :: [Char] +sentences = firstSen ++ secondSen + ++ thirdSen ++ fourthSen + +myLines :: String -> [String] +myLines [] = [] +myLines ('\n' : xs) = myLines xs +myLines xs = [takeWhile b xs] ++ (myLines (dropWhile b xs)) + where b = (/=) '\n' \ No newline at end of file diff --git a/09-lists/src/split.hs b/09-lists/src/split.hs new file mode 100644 index 0000000..1c823d7 --- /dev/null +++ b/09-lists/src/split.hs @@ -0,0 +1,25 @@ +module Split where + +-- Technically words and lines do not do the same thing. E.g +-- unwords . words $ " one two three " == "one two three" +-- unlines . lines $ "\none\n\ntwo\three" == "\none\n\ntwo\three\n" +-- i.e. words removes all spaces, lines splits between each '\n' +-- put otherwise: there are no empty words, but there are empty lines, +-- though there is no last empty line +-- The last part is evident by: lines "a\n" == ["a"] and lines "a" = ["a"] + +-- The function here sees no empty words nor does it see empty lines +mySplit :: [Char] -> Char -> [[Char]] +mySplit [] _ = [] +mySplit s@(x:xs) c + | x == c = mySplit xs c + | otherwise = [part1] ++ (mySplit part2 c) + where part1 = takeWhile b s + part2 = dropWhile b s + b = (/=) c + +myWords :: [Char] -> [[Char]] +myWords = flip mySplit $ ' ' + +myLines :: [Char] -> [[Char]] +myLines = flip mySplit $ '\n' \ No newline at end of file diff --git a/09-lists/src/squarecube.hs b/09-lists/src/squarecube.hs new file mode 100644 index 0000000..a330097 --- /dev/null +++ b/09-lists/src/squarecube.hs @@ -0,0 +1,18 @@ +module SquareCube where + + mySqr :: (Enum a, Num a) => [a] + mySqr = [x^(2 :: Integer) | x <- [1..5]] + + myCube :: (Enum a, Num a) => [a] + myCube = [y^(3 :: Integer) | y <- [1..5]] + + myTuples :: (Enum a, Num a) => [(a,a)] + myTuples = [(x,y) | x <- mySqr, y <- myCube] + + myTuples' :: (Ord a, Enum a, Num a) => [(a,a)] + myTuples' = [(x,y) | x <- mySqr, y <- myCube, + x < 50, y < 50] + + myTuples'Length :: Int + myTuples'Length = length (myTuples' :: [(Int,Int)]) + \ No newline at end of file diff --git a/09-lists/src/standards.hs b/09-lists/src/standards.hs new file mode 100644 index 0000000..4cb7633 --- /dev/null +++ b/09-lists/src/standards.hs @@ -0,0 +1,67 @@ +module Standards where + + -- 1 + myOr :: [Bool] -> Bool + myOr [] = True + myOr (x:xs) = x || myOr xs + + -- 2 + myAny :: (a -> Bool) -> [a] -> Bool + myAny _ [] = True + myAny f (x:xs) = f x || myAny f xs + + -- 3 + myElem :: Eq a => a -> [a] -> Bool + myElem _ [] = False + myElem a (x:xs) = (a == x) || myElem a xs + + myElem' :: Eq a => a -> [a] -> Bool + myElem' a = any (a==) + + -- 4 + myReverse :: [a] -> [a] + myReverse [] = [] + myReverse (x:xs) = myReverse xs ++ [x] + + -- 5 + squish :: [[a]] -> [a] + squish [] = [] + squish (x:xs) = x ++ squish xs + + -- 6 + squishMap :: (a -> [b]) -> [a] -> [b] + squishMap _ [] = [] + squishMap f (x:xs) = f x ++ squishMap f xs + + -- 7 + squishAgain :: [[a]] -> [a] + squishAgain = squishMap id + -- squishAgain = squishMap ([]++) + + -- 8 + myMaximumBy :: (a -> a -> Ordering) -> [a] -> a + myMaximumBy _ [] = undefined + myMaximumBy _ (x:[]) = x + myMaximumBy f (x:xs) = + case f x y of + LT -> y + _ -> x + where y = myMaximumBy f xs + + -- 9 + myMinimumBy :: (a -> a -> Ordering) -> [a] -> a + myMinimumBy _ [] = undefined + myMinimumBy _ (x:[]) = x + myMinimumBy f (x:xs) = + case f x y of + LT -> x + _ -> y + where y = myMinimumBy f xs + + -- 10 + myMaximum :: (Ord a) => [a] -> a + myMaximum = myMaximumBy compare + + myMinimum :: (Ord a) => [a] -> a + myMinimum = myMinimumBy compare + \ No newline at end of file diff --git a/09-lists/src/words.hs b/09-lists/src/words.hs new file mode 100644 index 0000000..0d28a34 --- /dev/null +++ b/09-lists/src/words.hs @@ -0,0 +1,7 @@ +module Words where + +myWords :: String -> [String] +myWords [] = [] +myWords (' ' : xs) = myWords xs +myWords xs = [takeWhile b xs] ++ (myWords (dropWhile b xs)) + where b = (/=) ' ' \ No newline at end of file diff --git a/09-lists/src/zipping.hs b/09-lists/src/zipping.hs new file mode 100644 index 0000000..91db6e5 --- /dev/null +++ b/09-lists/src/zipping.hs @@ -0,0 +1,14 @@ +module Zipping where + + zip :: [a] -> [b] -> [(a,b)] + zip [] _ = [] + zip _ [] = [] + zip (x:xs) (y:ys) = [(x,y)] ++ (Zipping.zip xs ys) + + zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] + zipWith _ [] _ = [] + zipWith _ _ [] = [] + zipWith f (x:xs) (y:ys) = [f x y] ++ (Zipping.zipWith f xs ys) + + zip' :: [a] -> [b] -> [(a,b)] + zip' = Zipping.zipWith (,) \ No newline at end of file