## Programming in Haskell by Graham Hutton

This book is what I used to learn the programming language Haskell. This page contains all my exercise answers.

*Source*: [Programming in Haskell, by Graham Hutton](https://people.cs.nott.ac.uk/pszgmh/pih.html)

* [Chapter 4 - Defining functions](#Chapter-4)
* [Chapter 5 - List comprehensions](#Chapter-5)
* [Chapter 6 - Recursive functions](#Chapter-6)

---

#### Chapter-4
##### Defining functions

###### exercise 1

```haskell
halve :: [Int] -> ([Int], [Int])
halve xs =    
  (take n xs, drop n xs)
  where n = length xs `div` 2

halve :: [Int] -> ([Int], [Int])
halve xs =    
    splitAt (length xs `div` 2) xs
```

###### exercise 2

```haskell
-- a (head & tail)
third :: [a] -> a
third xs = head (tail (tail xs))

-- b (list indexing)
third :: [a] -> a
third xs = xs !! 2

-- c (pattern matching)
third :: [a] -> a
third (_:_:a:_) = a
```

###### exercise 3

```haskell
-- a (conditional expression)
safetail :: [a] -> [a]
safetail xs = if length xs > 0 then tail xs else []

-- b (guarded equation)
safetail :: [a] -> [a]
safetail xs | length xs > 0 = tail xs
            | otherwise = []

-- c (pattern matching)
safetail :: [a] -> [a]
safetail [] = []
safetail xs = tail xs
  -- or:
  -- safetail (_:xs) = xs
```

###### exercise 4

```haskell
(||) :: Bool -> Bool -> Bool
True || _ = True
_ || True = True
_         = False
```

###### exercise 5

```haskell
-- Use conditional expressions to define &&.
(<#>) :: Bool -> Bool -> Bool
a <#> b =
  if a then
    if b then True else False
  else
    False
```

###### exercise 6

```haskell
(<#>) :: Bool -> Bool -> Bool
a <#> b =
  if a then b else False
```

###### exercise 7

```haskell
mult :: Int -> Int -> Int -> Int
mult x y z = x*y*z

-- rewritten to use lambda functions.
mult :: Int -> (Int -> (Int -> Int))
mult = \x -> (\y -> (\z -> x * y * z))
```

###### exercise 8

[Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm)

```haskell
luhnDouble :: Int -> Int
luhnDouble x = x * 2 `mod` 9

luhn :: Int -> Int -> Int -> Int -> Bool
luhn a b c d = 
  sum ((map luhnDouble [a,c]) ++ [b,d]) `mod` 10 == 0

--ghci> luhn 1 7 8 4
--True
--ghci> luhn 4 7 8 3
--False
```

---

#### Chapter-5
##### List comprehensions

* exercise 1

```haskell
sum [x^2 | x <- [0..100]]
-- 338350
```

###### exercise 2

```haskell
grid :: Int -> Int -> [(Int, Int)]
grid n m =
  [(x,y) | x <- [0..n], y <- [0..m]]

ghci> grid 1 2
-- [(0,0),(0,1),(0,2),(1,0),(1,1),(1,2)]
```

###### exercise 3

```haskell
square :: Int -> [(Int,Int)]
square n = 
  [(x,y) | (x,y) <- grid n n, x /= y]

ghci> square 2
-- [(0,1),(0,2),(1,0),(1,2),(2,0),(2,1)]
```

###### exercise 4

```haskell
replicate :: Int -> a -> [a]
replicate n item =
  [item | _ <- [1..n]]

ghci> replicate 4 "test"
-- ["test","test","test","test"]
```

###### exercise 5

[Pythagorean theorem](https://en.wikipedia.org/wiki/Pythagorean_theorem)

```haskell
isPythagorean :: Int -> Int -> Int -> Bool
isPythagorean x y z = 
  x^2 + y^2 == z^2

pyths :: Int -> [(Int,Int,Int)]
pyths n = 
  [(x,y,z) | x <- [1..n], y <- [1..n], z <- [1..n], isPythagorean x y z]

ghci> pyths 10
-- [(3,4,5),(4,3,5),(6,8,10),(8,6,10)]
```

###### exercise 6

[Perfect number](https://en.wikipedia.org/wiki/Perfect_number)

```haskell
factors :: Int -> [Int]
factors n = [x | x <- [1..n], n `mod` x == 0]

perfects :: Int -> [Int]
perfects limit = 
  [x | x <- [1..limit], sum (factors x) - x == x]

ghci> perfects 10000
-- [6,28,496,8128]
```

###### exercise 7 
*(I did not understand this one)*

###### exercise 8

Use the **find** library function in [Data.List 9.8.2](https://downloads.haskell.org/ghc/9.8.2/docs/libraries/base-4.19.1.0-179c/Data-List.html#v:find)

```haskell
find :: (a -> Bool) -> [a] -> Maybe a
-- The find function takes a predicate and a list and returns the first element in the list matching the predicate, or Nothing if there is no such element.
```

```haskell
positions :: Eq a => a -> [a] -> [Int]
positions x xs =
  [i | (x',i) <- zip xs [0..], x == x']

-- using find function, though I doubt its correct...

positions :: Eq a => a -> [a] -> [Int]
positions x xs = 
  [i | (x',i) <- zip xs [0..], isJust (find (==x) [x'])]

positions 2 [1,1,0,2,46,6,8,9,2,3,4,2,4,9,2] 
-- [3,8,11,14]

-- You can also use:
positions :: Eq a => a -> [a] -> [Int]
positions x = elemIndices x
```

###### exercise 9

[Scalar product](https://en.wikipedia.org/wiki/Dot_product)

```haskell
scalarproduct :: [Int] -> [Int] -> Int
scalarproduct xs ys =
  sum [x*y | (x,y) <- zip xs ys]

ghci> scalarproduct [1,2,3] [4,5,6]
-- 32
```

###### execise 10

[Caesar's Cipher](./caesar-cipher)

---

#### Chapter-6
##### Recursive functions