parent
d7b08372e7
commit
f882643891
50 changed files with 958 additions and 0 deletions
@ -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` |
@ -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` |
@ -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`. |
||||||
|
|
@ -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`. |
@ -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 |
@ -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 |
@ -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 |
@ -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" |
@ -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. |
@ -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 |
@ -0,0 +1,2 @@ |
|||||||
|
# Exercises: Eq Instances |
||||||
|
see src/eqinstances.hs |
@ -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)` |
||||||
|
|
@ -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` |
@ -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 |
@ -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" |
||||||
|
|
@ -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) |
@ -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 |
||||||
|
|
@ -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` |
@ -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))` |
||||||
|
|
@ -0,0 +1,2 @@ |
|||||||
|
#Exercises: Case Practise |
||||||
|
see src/casepractise.hs |
@ -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 |
@ -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` |
@ -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 |
@ -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 |
@ -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 |
@ -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 |
||||||
|
``` |
@ -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 |
@ -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 |
@ -0,0 +1,6 @@ |
|||||||
|
module McCarthy91 where |
||||||
|
|
||||||
|
mc91 :: (Integral a) => a -> a |
||||||
|
mc91 n |
||||||
|
| n > 100 = n - 10 |
||||||
|
| otherwise = mc91 . mc91 $ n + 11 |
@ -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 |
@ -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 |
@ -0,0 +1,2 @@ |
|||||||
|
# Exercises: Filtering |
||||||
|
see src/filtering.hs |
@ -0,0 +1,2 @@ |
|||||||
|
# Zipping Exercises |
||||||
|
see src/zipping.hs |
@ -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 |
@ -0,0 +1,2 @@ |
|||||||
|
# Exercise: EnumFromTo |
||||||
|
see src/enumfromto.hs |
@ -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 |
@ -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)]` |
@ -0,0 +1,2 @@ |
|||||||
|
# Exercises: Square Cube |
||||||
|
see src/squarecube.hs |
@ -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. |
@ -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))` |
@ -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 |
@ -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' |
@ -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 |
@ -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 |
||||||
|
|
@ -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' |
@ -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' |
@ -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)]) |
||||||
|
|
@ -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 |
||||||
|
|
@ -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 = (/=) ' ' |
@ -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 (,) |
Loading…
Reference in new issue