├── etc
└── haskell.png
├── src
├── 04-induction
│ ├── exercise_01.jpg
│ ├── exercise_02.jpg
│ ├── exercise_03.jpg
│ ├── exercise_04.jpg
│ ├── exercise_05.jpg
│ ├── exercise_06.jpg
│ ├── exercise_07.jpg
│ ├── exercise_08.jpg
│ ├── exercise_09.jpg
│ ├── exercise_16.jpg
│ ├── exercise_19.jpg
│ ├── exercise_20.jpg
│ ├── exercise_23.jpg
│ ├── exercise_10-11.jpg
│ ├── exercise_12-14.jpg
│ ├── exercise_17-18.jpg
│ ├── exercise_25-27.jpg
│ ├── exercises.hs
│ └── README.md
├── x-haskell
│ ├── Geometry
│ │ ├── Sphere.hs
│ │ ├── Cube.hs
│ │ └── Cuboid.hs
│ ├── monoid.hs
│ ├── Geo.hs
│ └── modules.hs
├── 05-trees
│ ├── TreePrinter.hs
│ ├── Notes.hs
│ └── Exercises.hs
├── 01-introduction-to-haskell
│ ├── data-type-definitions.hs
│ ├── types.hs
│ ├── operators.hs
│ ├── higher-order-functions.hs
│ ├── recursion.hs
│ ├── typeclasses.hs
│ ├── list-comprehension.hs
│ ├── data-structures.hs
│ ├── functions.hs
│ └── exercises.hs
├── 03-recursion
│ ├── data-recursion.hs
│ ├── notes.hs
│ └── exercises.hs
└── 02-equational-reasoning
│ └── notes.hs
├── ebooks
└── discrete-mathematics-using-computer.pdf
├── .gitignore
├── LICENSE
└── README.md
/etc/haskell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/etc/haskell.png
--------------------------------------------------------------------------------
/src/04-induction/exercise_01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_01.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_02.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_03.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_04.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_05.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_05.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_06.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_06.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_07.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_07.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_08.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_08.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_09.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_09.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_16.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_19.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_19.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_20.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_20.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_23.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_10-11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_10-11.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_12-14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_12-14.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_17-18.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_17-18.jpg
--------------------------------------------------------------------------------
/src/04-induction/exercise_25-27.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/src/04-induction/exercise_25-27.jpg
--------------------------------------------------------------------------------
/ebooks/discrete-mathematics-using-computer.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryukinix/discrete-mathematics/HEAD/ebooks/discrete-mathematics-using-computer.pdf
--------------------------------------------------------------------------------
/src/x-haskell/Geometry/Sphere.hs:
--------------------------------------------------------------------------------
1 | module Geometry.Sphere
2 | ( volume
3 | , area
4 | ) where
5 |
6 | volume :: (Floating r) => r -> r
7 | volume r = (4/3) * pi * (r ** 3)
8 |
9 | area :: (Floating r) => r -> r
10 | area r = 4 * pi * (r ** 2)
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | dist-*
3 | cabal-dev
4 | *.o
5 | *.hi
6 | *.chi
7 | *.chs.h
8 | *.dyn_o
9 | *.dyn_hi
10 | .hpc
11 | .hsenv
12 | .cabal-sandbox/
13 | cabal.sandbox.config
14 | *.prof
15 | *.aux
16 | *.hp
17 | *.eventlog
18 | .stack-work/
19 | cabal.project.local
20 |
--------------------------------------------------------------------------------
/src/x-haskell/Geometry/Cube.hs:
--------------------------------------------------------------------------------
1 | module Geometry.Cube
2 | ( volume
3 | , area) where
4 |
5 | import qualified Geometry.Cuboid as Cuboid
6 |
7 | volume :: (Floating a) => a -> a
8 | volume a = Cuboid.volume a a a
9 |
10 | area :: (Floating a) => a -> a
11 | area a = Cuboid.area a a a
12 |
--------------------------------------------------------------------------------
/src/x-haskell/monoid.hs:
--------------------------------------------------------------------------------
1 | {-# LANGUAGE FlexibleInstances #-}
2 | {-# LANGUAGE TypeSynonymInstances #-}
3 | -- example given on
4 | -- https://bartoszmilewski.com/2014/12/05/categories-great-and-small/
5 |
6 | class Monoid' m where
7 | mempty' :: m
8 | mappend' :: m -> m -> m
9 |
10 |
11 | instance Monoid' String where
12 | mempty' = ""
13 | mappend' = (++)
14 |
15 | main = print $ mappend' "Hello, " "Monoid!"
16 |
--------------------------------------------------------------------------------
/src/x-haskell/Geometry/Cuboid.hs:
--------------------------------------------------------------------------------
1 | module Geometry.Cuboid
2 | ( volume
3 | , area
4 | ) where
5 |
6 | volume :: (Fractional a) => a -> a -> a -> a
7 | volume a b c = rectangleArea a (b * c)
8 |
9 | area :: (Fractional a) => a -> a -> a -> a
10 | area a b c = 2 * rectangleArea a b
11 | + 2 * rectangleArea b c
12 | + 2 * rectangleArea a c
13 |
14 | rectangleArea :: (Fractional a) => a -> a -> a
15 | rectangleArea a b = a * b
16 |
--------------------------------------------------------------------------------
/src/05-trees/TreePrinter.hs:
--------------------------------------------------------------------------------
1 | module TreePrinter
2 | (prettyTree) where
3 |
4 | import Notes (BinTree(Node, Leaf))
5 |
6 | prettyTree :: (Show a) => BinTree a -> Int -> String
7 | prettyTree Leaf _ = ""
8 | prettyTree (Node a left right) d = (replicate d ' ') ++ "=> " ++ show a ++ "\n"
9 | ++ lookBranch left ++ lookBranch right
10 | where lookBranch b = prettyTree b (d + 3)
11 |
12 | instance (Show a) => Show (BinTree a) where
13 | show t = prettyTree t 0
14 |
--------------------------------------------------------------------------------
/src/x-haskell/Geo.hs:
--------------------------------------------------------------------------------
1 | module Geo
2 | ( sphereVolume
3 | , sphereArea
4 | , cubeVolume
5 | , cubeArea
6 | , cuboidVolume
7 | , cuboidArea
8 | ) where
9 |
10 |
11 | sphereVolume :: Float -> Float
12 | sphereVolume radius = (4.0 / 3.0) * pi * (radius ** 3)
13 |
14 | sphereArea :: Float -> Float
15 | sphereArea radius = 4 * pi * (radius ** 2)
16 |
17 | cubeVolume :: Float -> Float
18 | cubeVolume side = cuboidVolume side side side
19 |
20 | cubeArea :: Float -> Float
21 | cubeArea side = cuboidArea side side side
22 |
23 | cuboidVolume :: Float -> Float -> Float -> Float
24 | cuboidVolume a b c = rectangleArea a b * c
25 |
26 | cuboidArea :: Float -> Float -> Float -> Float
27 | cuboidArea a b c = rectangleArea a b * 2 + rectangleArea a c * 2 + rectangleArea c b * 2
28 |
29 | rectangleArea :: Float -> Float -> Float
30 | rectangleArea a b = a * b
31 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/data-type-definitions.hs:
--------------------------------------------------------------------------------
1 | {-- Data Type Definitions --}
2 |
3 | data Colour = Red | Orange | Yellow
4 | | Green | Blue | Violet
5 | deriving Show
6 |
7 | -- A custom user-defined type for enumerates colors
8 |
9 | data Animal a b = Cat a | Dog b | Rat
10 | deriving Show
11 |
12 |
13 | data BreedOfCat = Siamese | Persian | Moggie
14 | deriving (Show, Eq)
15 |
16 | -- Deriving is like inherits properties from other type classes.
17 |
18 | -- The Monad Maybe wrapping a value
19 | -- data Maybe a = Nothing | Just a
20 | -- When using it? Example:
21 | phoneMessage :: Maybe Integer -> String
22 | phoneMessage Nothing = "Telephone number not found"
23 | phoneMessage (Just x) = "The number is " ++ show x
24 |
25 | -- If a function has a possibility of variability in our type result/input
26 | -- We can use Maybe Monad to handling that.
27 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/types.hs:
--------------------------------------------------------------------------------
1 | {--
2 | Just a simple and common types on Haskell
3 |
4 | Int stands for integer with fixed precision
5 | Integer stands for a integer with arbitrary precision (BigNum)
6 | Float is real floating point with single precision
7 | Double is a real floating point with double the precision
8 | Bool is a boolean type. It can have only two values: True and False.
9 | Char represents a character. It's denoted by single quotes.
10 | String is a list of characters.
11 | IO handles Input and Output
12 |
13 | --}
14 |
15 |
16 |
17 | -- Number types
18 | int :: Int
19 | integer :: Integer
20 | float :: Float
21 | rational :: Rational
22 |
23 | -- Logic type
24 | bool :: Bool
25 |
26 | -- IO () (Input/Output)
27 | main :: IO ()
28 |
29 | int = 1
30 | integer = 2 ^ 100
31 | float = 3/4
32 | rational = 3/4
33 | bool = True
34 |
35 | main = do print int
36 | print integer
37 | print float
38 | print rational
39 | print bool
40 |
--------------------------------------------------------------------------------
/src/04-induction/exercises.hs:
--------------------------------------------------------------------------------
1 | {-- EXERCISES --}
2 |
3 | -- Exercise 22
4 | -- Assume there is a function called max that delivers the larger of
5 | -- its two arguments
6 | -- max x y = x | if x >= y
7 | -- max x y = y | if y >= x
8 | -- Write a function maximum that, given a non-empty sequence of values
9 | -- whose sizes can be compared (that is values from a type of class Ord)
10 | -- delivers the largest value in the sequence
11 |
12 | maximum' :: (Ord a) => [a] -> a
13 | maximum' [] = error "empty list"
14 | maximum' [x] = x
15 | maximum' (x:xs) = max x (maximum' xs)
16 |
17 | -- Exercise 24
18 | -- Write a function that, given a sequence containing only non-empty
19 | -- sequences, delivers the sequence made up of the first elements of
20 | -- each of those non-empty sequences.
21 |
22 | concat' :: [[a]] -> [a]
23 | concat' [[]] = []
24 | concat' [xs] = xs
25 | concat' (xs:xss) = xs ++ concat' xss
26 |
27 |
28 | -- Exercise 26
29 | -- Define an `and` operator using && and foldr
30 |
31 | and' :: [Bool] -> Bool
32 | and' xs = foldr (&&) True xs
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Manoel Machado
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/operators.hs:
--------------------------------------------------------------------------------
1 | {--
2 | The mostly commons operators for basic logic in Haskell
3 | --}
4 |
5 |
6 | -- the declaration of function with multiple params
7 | -- is done that way because the currying. Reducing
8 | -- functions to just a dataflow. So do this is wrong:
9 | -- and :: (Bool, Bool) -> Bool
10 | -- This means that a function and receives a tuple (Bool, Bool) as its
11 | -- unique argument and returns a Bool
12 |
13 | -- btw, makes some sense on a structured language.
14 | -- HASKELL IS NOT A STRUCTURED LANGUAGE!
15 |
16 | -- :: DECLARATIONS
17 | eq :: Integer -> Integer -> Bool
18 | greater :: Integer -> Integer -> Bool
19 | greater'eq :: Integer -> Integer -> Bool
20 | less :: Integer -> Integer -> Bool
21 | less'eq :: Integer -> Integer -> Bool
22 | not'equal :: Bool -> Bool -> Bool
23 | and :: Bool -> Bool -> Bool
24 | or :: Bool -> Bool -> Bool
25 | not' :: Bool -> Bool
26 |
27 | -- :: DEFINITIONS
28 | eq x y = x == y
29 | greater x y = x > y
30 | greater'eq x y = x >= y
31 | less x y = x < y
32 | less'eq x y = x <= y
33 | not'equal x y = x /= y
34 | and x y = x && y
35 | or x y = x || y
36 | not' x = not x
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Abstract
2 |
3 | This project is designed to help computer science students to create a heavy
4 | relation with its journey about mathematics using haskell to understand the
5 | fundamentals of computer science and discrete mathematics.
6 |
7 | 
8 |
9 | # Goal
10 |
11 | The main target of this repository is use git to save all the solutions of book
12 | exercises explaining really easily the mathematics concepts envolved
13 | as well the Haskell too.
14 |
15 | # Reading [120/442]
16 | 
17 |
18 | - [x] Section I: Programming and Reasoning with Equations
19 | - [x] Chapter 1: Introduction to Haskell
20 | - [x] Chapter 2: Equational Reasoning
21 | - [x] Chapter 3: Recursion
22 | - [x] Chapter 4: Induction
23 | - [x] Chapter 5: Trees
24 | - [ ] Section II: Logic
25 | - [ ] Chapter 6: Propositional Logic
26 | - [ ] Chapter 7: Predicate Logic
27 | - [ ] Section III: Set Theory
28 | - [ ] Chapter 8: Set Theory
29 | - [ ] Chapter 9: Inductively Defined Sets
30 | - [ ] Chapter 10: Relations
31 | - [ ] Chapter 11: Functions
32 | - [ ] Section IV: Applications
33 | - [ ] Chapter 12: The AVL Tree Miracle
34 | - [ ] Chapter 13: Discrete Mathematics in Circuit Design
35 |
36 | # Authors
37 |
38 | * [Manoel Machado](https://www.github.com/ryukinix)
39 |
40 | # License
41 | [MIT](LICENSE)
42 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/higher-order-functions.hs:
--------------------------------------------------------------------------------
1 | {-- HIGHER ORDER FUNCTIONS --}
2 |
3 | -- The function twice receive a function and
4 | -- its argument and apply two times on it.
5 | twice :: (a->a) -> a -> a
6 | twice f x = f (f x)
7 |
8 |
9 | prod :: Integer -> Integer -> Integer
10 | prod x y = x * y
11 | g = prod 4 -- partial application! this is a function
12 | p = g 6 -- 24
13 | q = twice g 3 -- => 48
14 |
15 | -- foldr, foldl as reduce/accumulator
16 | fat :: Integer -> Integer
17 | fat n = foldr (*) 1 [1..n]
18 |
19 | -- mapping values using map
20 | s = map (\n -> n + 1) [1..10]
21 | -- => sum +1 for each value of [1..10]
22 | -- => [2,3,4,5,6,7,8,9,10,11]
23 |
24 |
25 | -- zipWith definition
26 | zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
27 | zipWith' _ [] _ = []
28 | zipWith' _ _ [] = []
29 | zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys
30 |
31 | -- fliping function arguments
32 | flip' :: (a -> b -> c) -> (b -> a -> c)
33 | flip' f = g
34 | where g x y = f y x
35 |
36 |
37 | -- filtering
38 | evens1to10 = filter even [1..10]
39 |
40 | largestDivisible :: (Integral a) => a
41 | largestDivisible = head (filter p [100000, 99999..])
42 | where p x = x `mod` 3829 == 0
43 |
44 | -- takeWhile get the the values until condition matchs
45 | n = sum $ takeWhile (<10000) $ filter odd $ map (^2) $ [1..]
46 | v = takeWhile (/=' ') "bananas assadas" -- bananas
47 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/recursion.hs:
--------------------------------------------------------------------------------
1 | {-- RECURSION
2 |
3 | The code of this file was stoled with learning purposes
4 | from learnyouahaskell.com/recursion
5 |
6 | --}
7 |
8 | maximum' :: (Ord a) => [a] -> a
9 | maximum' [] = error "maximum of empty list"
10 | maximum' [x] = x
11 | maximum' (x:xs)
12 | | x > maxTail = x
13 | | otherwise = maxTail
14 | where maxTail = maximum' xs
15 |
16 | -- a clever way
17 | maximum'' :: (Ord a) => [a] -> a
18 | maximum'' [] = error "maximum of empty list"
19 | maximum'' [x] = x
20 | maximum'' (x:xs) = max x (maximum'' xs)
21 |
22 |
23 | -- replicate a number n x times
24 | replicate' :: (Num i, Ord i) => i -> a -> [a]
25 | replicate' n x
26 | | n <= 0 = []
27 | | otherwise = x:replicate' (n-1) x
28 |
29 | -- replicate 3 5 => [5,5,5]
30 |
31 |
32 | -- take n elements from a list
33 | take' :: (Num i, Ord i) => i -> [a] -> [a]
34 | take' n _
35 | | n <= 0 = []
36 | take' _ [] = []
37 | take' n (x:xs) = x : take' (n-1) xs
38 |
39 | -- infinite lists
40 | repeat' :: a -> [a]
41 | repeat' x = x:repeat' x
42 |
43 | zip' :: [a] -> [b] -> [(a,b)]
44 | zip' _ [] = []
45 | zip' [] _ = []
46 | zip' (x:xs) (y:ys) = (x,y):zip' xs ys
47 |
48 |
49 | elem' :: (Eq a) => a -> [a] -> Bool
50 | elem' a [] = False
51 | elem' a (x:xs)
52 | | a == x = True
53 | | otherwise = a `elem'` xs
54 |
55 |
56 | quicksort :: (Ord a) => [a] -> [a]
57 | quicksort [] = []
58 | quicksort (x:xs) =
59 | let smallerSorted = quicksort [a | a <- xs, a <= x]
60 | biggerSorted = quicksort [a | a <- xs, a > x]
61 | in smallerSorted ++ [x] ++ biggerSorted
62 |
--------------------------------------------------------------------------------
/src/04-induction/README.md:
--------------------------------------------------------------------------------
1 | # Handwritten Answers
2 |
3 | # Mathematical Induction
4 | Just mathematical induction through the natural numbers.
5 |
6 | ## Exercise 1
7 | 
8 | ## Exercise 2
9 | 
10 | ## Exercise 3
11 | 
12 | ## Exercise 4
13 | 
14 |
15 | # List Induction
16 | The real part to prove recursive programs that handles lists.
17 |
18 | ## Exercise 5
19 | 
20 |
21 | ## Exercise 6
22 | 
23 |
24 | ## Exercise 7
25 | 
26 |
27 | ## Exercise 8
28 | 
29 |
30 | ## Exercise 9
31 | 
32 |
33 | ## Exercise 10-11
34 | 
35 |
36 | ## Exercise 12-14
37 | 
38 |
39 | ## Exercise 15
40 | HAHAHA, the exercise 15 was so stupid that I forgot to solve it.
41 | Was just it:
42 | > Evaluate [1,2,3] for theorem 27 and check if is true.:
43 |
44 | ```haskell
45 | -- theorem 27
46 | (reverse (reverse xs)) = xs
47 | ```
48 |
49 | Whose, in that case, stands for true.
50 | The problem with this is theorem is just for
51 | when xs is a infinite list. For finite lists this works fine.
52 |
53 | # Exercise 16
54 | 
55 |
56 | ## Exercise 17-18
57 | 
58 |
59 | ## Exercise 19
60 | 
61 |
62 | ## Exercise 20
63 | 
64 |
65 | ## Exercise 23
66 | 
67 |
68 | ## Exercise 25-27
69 | 
70 |
71 |
72 | ## Haskell Solutions
73 |
74 | * Exercise [22, 24 and 26](exercises.hs)
75 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/typeclasses.hs:
--------------------------------------------------------------------------------
1 | {-- Basic Haskell Typeclasses
2 |
3 | Type classes are similar to interfaces on another languages.
4 |
5 | A Type Class stands for its members have common properties in
6 | a group of types.
7 |
8 | On type declaration, the first part of an implication (=>)
9 | are the type class constraints using Typeclasses. This ensures
10 | that the determined type variables are members of the given typeclass.
11 |
12 | * Eq is used for types that support equality testing.
13 | * Ord is for types that have an ordering
14 | * Show has the property of your members can be presented as strings.
15 | * Read is sort of the opposite typeclass of Show.
16 | * Enum members are sequentially ordered types -- they can be enumerated.
17 | * Bounded members have an upper and a lower bound
18 | * Num is a numeric typeclass.
19 | * Integral is a subset of Num including the whole numbers: Int and Integer
20 | * Floating is a subset of Num including only real nums: Float and Double.
21 | --}
22 |
23 |
24 | fat1 :: (Integral a) => a -> a
25 | fat1 n = product [1..n]
26 |
27 |
28 | lucky :: (Integral a) => a -> String
29 | lucky 7 = "LUCKY NUMBER SEVEN!"
30 | lucky x = "Sorry, you're out of luck, pal!"
31 |
32 | sayMe :: (Integral a) => a -> String
33 | sayMe 1 = "One!"
34 | sayMe 2 = "Two!"
35 | sayMe 3 = "Three!"
36 | sayMe 4 = "Four!"
37 | sayMe 5 = "Five!"
38 | sayMe x = "Not between 1 and 5"
39 |
40 | addVectors :: (Num a) => (a, a) -> (a, a) -> (a, a)
41 | addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
42 |
43 | first :: (a, b, c) -> a
44 | first (x, _, _) = x
45 |
46 | second :: (a, b, c) -> b
47 | second (_, y, _) = y
48 |
49 | third :: (a, b, c) -> c
50 | third (_, _, z) = z
51 |
52 | length' :: (Num b) => [a] -> b
53 | length' [] = 0
54 | length' (_:xs) = 1 + length' xs
55 |
56 | sum' :: (Num a) => [a] -> a
57 | sum' [] = 0
58 | sum' (x:xs) = x + sum' xs
59 |
60 |
61 | capital :: String -> String
62 | capital "" = "Empty string, whoops!"
63 | capital all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x]
64 |
--------------------------------------------------------------------------------
/src/x-haskell/modules.hs:
--------------------------------------------------------------------------------
1 | -- This notes comes from learnyouahaskell.com/modules
2 |
3 | -- exists a lot of ways to import external modules on haskell
4 | import Data.List -- put all Data.List definitions on the global namespace
5 | import Data.List (sort, nub) -- only import sort and nub
6 | import Data.List hiding (sort) -- import all from Data.List, except for sort
7 | import qualified Data.Map as Map -- import this module as reserved namespace M
8 | import Data.Char
9 | import Data.Function (on)
10 | import qualified Data.Set as Set
11 |
12 | -- brief examples of combined functions from Data.List, Data.Char and Data.Function
13 | pythonSplit a s = filter (not . any isChar) . groupBy ((==) `on` isChar) $ s
14 | where isChar = (== a)
15 |
16 | commaInts :: String -> [Int]
17 | commaInts s = map read $ pythonSplit ',' s
18 |
19 | pythonJoin = intercalate
20 |
21 | encode :: Int -> String -> String
22 | encode shift msg =
23 | let ords = map ord msg
24 | shifted = map (+ shift) ords
25 | in map chr shifted
26 |
27 | decode :: Int -> String -> String
28 | decode shift = encode (negate shift)
29 |
30 | -- The main proposal of Data.Map
31 |
32 |
33 | -- a naive implementation of findKey for association lists
34 | findKey :: (Eq k) => k -> [(k,v)] -> v
35 | findKey k xs = snd . head . filter (\(a,b) -> k == a) $ xs
36 |
37 |
38 | -- a more secure using the maybe monad
39 | findKey' :: (Eq k) => k -> [(k,v)] -> Maybe v
40 | findKey' _ [] = Nothing
41 | findKey' key ((k,v):xs) = if key == k
42 | then Just v
43 | else findKey' key xs
44 |
45 | -- association lists are a primitive way to dealing with
46 | -- key-value store. Instead that we can use the Map.Map
47 | -- which are more efficient because the data are stored
48 | -- in a tree
49 |
50 |
51 | -- Map.Map
52 | -- Map.empty
53 | -- Map.insert
54 | -- Map.null
55 | -- Map.lookup
56 | -- Map.singleton
57 | -- Map.map
58 | -- Map.filter
59 | -- Map.member
60 | -- Map.keys
61 | -- Map.elems
62 | -- Map.fromList
63 | -- Map.toList
64 | -- Map.fromListWith
65 | -- Map.insertWith
66 |
67 | -- This above are the mainly used functions from the
68 | -- Data.Map module.
69 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/list-comprehension.hs:
--------------------------------------------------------------------------------
1 | {-- List Comprehension
2 |
3 | List comprehension is Haskell is very similar to set comprehension
4 | in Mathematics. A list comprehension has this form:
5 |
6 | [expression | generator]
7 |
8 | The generator specifies a sequence of values that a variable takes on.
9 | This is written in the form var <- list, and it means that the variable var
10 | will take on each of the values in list, one by one. For each of those values,
11 | the expression to the left of the bar is evaluated.
12 |
13 | --}
14 |
15 | import Data.Char (toLower)
16 |
17 | multiplesOfTen :: [Int]
18 | squares :: [Int]
19 | lowering :: String
20 |
21 | multiplesOfTen = [10 * x | x <- [1, 2, 3]]
22 | -- => [10, 20, 30]
23 | squares = [x ^ 2 | x <- [1..5]]
24 | lowering = [toLower c | c <- "Too Many CAPITALs"]
25 |
26 | -- destructuring bind
27 | ab = [a * b | (a,b) <- [(1,2),(10,20), (6,6)]]
28 | -- => [2,200,36]
29 |
30 | -- multiples generators acting combinators or nested loops
31 | xy :: [(Int, Char)]
32 | xy = [(x, y) | x <- [1,2,3], y <- ['a', 'b']]
33 | -- => [(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')]
34 |
35 | -- specifying conditions to filter
36 | multiplesOfTwoAndSeven = [x | x <- [0..100],
37 | x `mod` 2 == 0 && x `mod` 7 == 0]
38 | -- => [0,14,28,42,56,70,84,98]
39 |
40 | -- Creating a list of factors of 12
41 | factorsOfTwelve = [x | x <- [1..12],
42 | y <- [1..12],
43 | 12 == x*y]
44 |
45 | -- Exercise 2.
46 |
47 | emptyList = [x | x <- [1, 2, 3], False]
48 | -- => []
49 |
50 | nandTruthTable = [not (x && y) | x <- [False, True],
51 | y <- [False, True]]
52 | -- => [True, True, True, False]
53 |
54 | justTrue = [x || y | x <- [False, True],
55 | y <- [False, True],
56 | x /= y]
57 | -- => [True, True]
58 |
59 | sphereCoordinates = [[x,y,z] | x <- [1..50],
60 | y <- [1..50],
61 | z <- [1..50],
62 | x ^ 2 + y ^ 2 == z ^ 2]
63 | -- => [[3,4,5],[4,3,5],[5,12,13],[6,8,10],[7,24,25],[8,6,10],[8,15,17],...]
64 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/data-structures.hs:
--------------------------------------------------------------------------------
1 | {--
2 | A few examples of basic structures on Haskell
3 |
4 | Tuples, Lists and Strings
5 |
6 | --}
7 |
8 | import Data.Char (toUpper, toLower) -- importing toUpper and toLower
9 | import Text.Printf
10 |
11 |
12 | -- STRINGS AND CHARS
13 | {--
14 | Strings are made by char elements.
15 | A elemental string can be see as a list of chars.
16 |
17 | > ['a', 'b', 'c', 'd'] == "abcd"
18 | => True
19 |
20 | Single quotes denotes characters.
21 | Double quotes denotes strings.
22 | --}
23 |
24 |
25 | upperChar :: Char
26 | lowerChar :: Char
27 | upperString :: String
28 |
29 | upperChar = toUpper 'w' -- => 'W'
30 | lowerChar = toLower upperChar -- => 'w'
31 | upperString = map toUpper "asdf" -- => "ASDF"
32 |
33 | {-- TUPLES AND LISTS
34 |
35 | tuple_example = ('a', 'b', 'c')
36 | => A tuple of length three containing the characters a, b and c.
37 | list_example = ['a', 'b', 'c']
38 | => A list of length three containing the characters a, b and c.
39 |
40 | Types =>
41 | tuple_example :: (Char, Char, Char)
42 | list_example :: [Char]
43 |
44 | :: Tuples
45 |
46 | Tuples have two important characteristics. First, a tuple has
47 | a fixed number of components. If you have a 3-tuple (a, b, c),
48 | and you add an extra data value to obtain (a, b, c, d) the new tuple
49 | hash a different type from the old one. Second, there is no restriction
50 | on the type of any component: it is common for a tuple to contain data values
51 | with different types.
52 |
53 |
54 | :: Lists
55 |
56 | A list may contain any number of elements, but all of the elements must
57 | have the same type (homogeneous lists). The type of a list is written [A],
58 | where A is the element type.
59 |
60 | --}
61 |
62 | tupleOfStrings :: (String, String)
63 | tupleOfStrings = ("dog", "cat")
64 | dog = fst tupleOfStrings
65 | cat = snd tupleOfStrings
66 |
67 | nums :: [Int]
68 | catDog :: [String]
69 | nestedList :: [[Int]]
70 | nums = [13, 9, -2, 100]
71 | catDog = ["cat", "dog"]
72 | nestedList = [[1,2],[3,7,1], [], [900]]
73 |
74 | -- You can specify ranges using lists
75 | range1to10 = [1..10] :: [Int]
76 | alphabet = ['a'..'z'] :: [Char]
77 |
78 | -- As well we can define sequences
79 | sequence' = [10,8..0] :: [Int]
80 | -- => [10,8,6,4,2,0]
81 |
82 |
83 | -- List Notation and (:)
84 | listCons = 1:2:3:[]
85 | listSyntaxSugar = [1,2,3]
86 | isEqual = listCons == listSyntaxSugar
87 |
--------------------------------------------------------------------------------
/src/03-recursion/data-recursion.hs:
--------------------------------------------------------------------------------
1 | {-- Data Recursion Topic --}
2 |
3 | -- Peano Arithmetic
4 |
5 | -- We turn now to the implementation of arithmetic operations over
6 | -- a simple data structure representing the natural numbers. The reason
7 | -- for working with this representation is that it provides a good
8 | -- introduction to recursion over general algebraic types
9 |
10 | data Peano = Zero | Succ Peano
11 |
12 | peanoDecode :: Peano -> Integer
13 | peanoDecode Zero = 0
14 | peanoDecode (Succ x) = 1 + peanoDecode x
15 |
16 | instance Show Peano where
17 | show x = show $ peanoDecode x
18 |
19 | -- peanoDecode (Succ (Succ Zero)) == 2
20 | -- peanoDecode Zero == 0
21 |
22 | -- As you can see, the peano data type is recursive. In this case,
23 | -- the recursion builds up a series of constructor applications,
24 | -- somewhat like the list data type
25 |
26 | data List a = Empty | Cons a (List a)
27 |
28 | listDecode :: List a -> [a]
29 | listDecode Empty = []
30 | listDecode (Cons a b) = a : listDecode b
31 | -- listDecode (Cons 1 (Cons 2 (Cons 3 Empty))) == [1,2,3]
32 | -- listDecode Empty == []
33 |
34 | -- A few function to handle the Peano datatype
35 | decrement :: Peano -> Peano
36 | decrement Zero = Zero
37 | decrement (Succ a) = a
38 |
39 | add :: Peano -> Peano -> Peano
40 | add Zero b = b
41 | add (Succ a) b = Succ (add a b)
42 |
43 | sub :: Peano -> Peano -> Peano
44 | sub a Zero = a
45 | sub Zero b = Zero
46 | sub (Succ a) (Succ b) = sub a b
47 |
48 |
49 | equals :: Peano -> Peano -> Bool
50 | equals Zero Zero = True
51 | equals Zero b = False
52 | equals a Zero = False
53 | equals (Succ a) (Succ b) = equals a b
54 |
55 | instance Eq Peano where
56 | a == b = equals a b
57 |
58 |
59 | lt :: Peano -> Peano -> Bool
60 | lt a Zero = False
61 | lt Zero (Succ b) = True
62 | lt (Succ a) (Succ b) = lt a b
63 |
64 | instance Ord Peano where
65 | a < b = lt a b
66 | a >= b = (not $ lt a b)
67 | a <= b = lt a b || a == b
68 | a > b = not (a <= b)
69 |
70 | -- Data Recursion
71 |
72 | -- Another important programming technique uses recursion to define data
73 | -- structures; this is called data recursion
74 | -- The idea is to define circular data structures. Here is one way to define
75 | -- an infinitely long list where every element is 1.
76 |
77 | repeat' :: a -> [a]
78 | repeat' x = x : repeat' x
79 | ones = repeat' 1 -- infinite list of 1
80 |
81 |
82 | -- However, it's possible to represent ones very compactly with a circular list
83 | -- defined with recursion in the data rather than in a function
84 |
85 | twos = 2 : twos -- infinite list of 2
86 |
87 | -- A more tricky example
88 | fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
89 | -- Yes! The Fibonacci sequence! Infinite! One-liners is the power of Haskell
90 |
91 |
92 |
93 | main :: IO ()
94 | main = print $ take 20 twos
95 |
--------------------------------------------------------------------------------
/src/02-equational-reasoning/notes.hs:
--------------------------------------------------------------------------------
1 | {-- Equational Reasoning using Haskell --}
2 |
3 | {--
4 | One of the formal methods to proof is the equational reasoning.
5 | Nothing more than the school algebra with a few notations more.
6 |
7 | x = 8
8 | x = 4
9 |
10 | Suppose we wants evaluate the following expression:
11 |
12 |
13 | 2*x + x/y
14 | = 2 * 8 + 8/y { x }
15 | = 2 * 8 + 8/4 { y }
16 | = 16 + 2 { arithmetic }
17 | = 18 { arithmetic}
18 |
19 | 2 * x + x/y = 18
20 |
21 |
22 | The example above is just elementary mathematics, but exactly
23 | the same technique can be used to reason about Haskell programs.
24 | Because equations in Haskell are true mathematical equations
25 | -- they are not assignment statements.
26 |
27 | --}
28 |
29 | -- Equational Reasoning as Hand-execution
30 | -- We can use Equation Reasoning to proof the correctness of an algorithm
31 |
32 |
33 | f :: Integer -> Integer -> Integer
34 | f x y = (2+x) * g y
35 |
36 | g :: Integer -> Integer
37 | g z = 8 - z
38 |
39 | -- Hand execution
40 | {--
41 | f 3 4
42 | = (2 + 3) * g 4 { f }
43 | = (2 + 3) (8 - 4) { g }
44 | = 20 {arithmetic}
45 | --}
46 |
47 | -- Conditionals
48 |
49 | {--
50 | A conditional expression satisfies the following equations
51 |
52 | if True then e2 else e3 = e2 {if True}
53 | if False then e2 else e3 = e3 {if False}
54 | --}
55 |
56 |
57 | f' :: Double -> Double
58 | f' x =
59 | if x >= 0
60 | then sqrt x
61 | else 0
62 |
63 | -- f' 4 => 2.0
64 | -- f' -1 => 0
65 |
66 | -- EQUATIONAL REASONING WITH LISTS
67 |
68 |
69 | -- Theorem 1 (length (++))
70 | -- Let xs, ys :: [a] be arbitrary lists. Then:
71 | -- length (xs ++ ys) = length xs + length ys
72 |
73 | -- Theorem 2 (length map)
74 | -- Let xs :: [a] be an arbitrary list, and f :: a -> b an arbitrary function
75 | -- Then length (map f xs) = length xs
76 |
77 | -- Theorem 3 (map (++))
78 | -- Let xs, ys :: [a] be arbitrary lists, and let f :: a -> b be an arbitrary function.
79 | -- Then map f (xs ++ ys) = map f xs ++ map f ys
80 |
81 | -- Theorem 4
82 | -- For arbitrary lists xs, ys :: [a] and arbitrary f :: a -> b, the
83 | -- following equations holds:
84 | -- length (map f (xs ++ ys)) = length xs + length ys
85 |
86 |
87 | -- Proof Theorem 4 using as Lema Theorem 1,2,3
88 | {--
89 | length (map f (xs ++ ys))
90 | = length (map f xs ++ map f ys) { map (++) } (Theorem 3)
91 | = length (map f xs) + length (map f ys) { length (++) } (Theorem 1)
92 | = length xs + length ys { length map } (Theorem 2)
93 |
94 | --}
95 |
96 |
97 | -- NOTE: A variable in mathematics means "a name that stands for some value"
98 | -- while a variable in a imperative programming language means
99 | -- "a memory location whose value is modified by certain instructions"
100 |
--------------------------------------------------------------------------------
/src/05-trees/Notes.hs:
--------------------------------------------------------------------------------
1 | {-- TREES --}
2 | module Notes
3 | ( BinTree(Leaf, Node)
4 | , BinTreeInt(LeafInt, NodeInt)
5 | , inorder
6 | , posorder
7 | , preorder
8 | , reflect
9 | , size
10 | , height
11 | , binTreeIntToBinTree
12 | , balanced
13 | , linSearch
14 | , binSearch
15 | , insert
16 | ) where
17 |
18 | -- Binary Tree of Int nodes
19 |
20 | data BinTreeInt
21 | = LeafInt
22 | | NodeInt Int BinTreeInt BinTreeInt
23 |
24 |
25 | -- Binary Tree of a Arbitrary Type
26 |
27 |
28 | data BinTree a
29 | = Leaf
30 | | Node a (BinTree a) (BinTree a)
31 |
32 |
33 | -- Traversal modes
34 |
35 | preorder :: BinTree a -> [a]
36 | preorder Leaf = []
37 | preorder (Node a l r) = [a] ++ preorder l ++ preorder r
38 |
39 | inorder :: BinTree a -> [a]
40 | inorder Leaf = []
41 | inorder (Node a l r) = inorder l ++ [a] ++ inorder r
42 |
43 | posorder :: BinTree a -> [a]
44 | posorder Leaf = []
45 | posorder (Node a l r) = posorder l ++ posorder r ++ [a]
46 |
47 |
48 | -- Processing Tree Structure
49 |
50 | -- given a BinTree returns a reflected BinTree
51 | -- (swaps the branchs of each node)
52 | reflect :: BinTree a -> BinTree a
53 | reflect Leaf = Leaf
54 | reflect (Node a l r) = Node a (reflect r) (reflect l)
55 |
56 | -- given a BinTree returns a Int number called height
57 | -- based on the current node and the deepest node on the tree
58 | height :: BinTree a -> Integer
59 | height Leaf = 0
60 | height (Node a l r) = 1 + max (height l) (height r)
61 |
62 |
63 | -- given a BinTree returns a Int number called size
64 | -- based on the count of nodes on the tree
65 | size :: BinTree a -> Integer
66 | size Leaf = 0
67 | size (Node a l r) = 1 + size l + size r
68 |
69 | -- given a BinTree returns True if the tree is fully
70 | -- balanced and Fals otherwise
71 | balanced :: BinTree a -> Bool
72 | balanced Leaf = True
73 | balanced (Node _ l r) =
74 | height l == height r && balanced l && balanced r
75 |
76 |
77 | -- :: Search Algorithms
78 |
79 | -- Linear Search
80 | linSearch :: (Eq a) => a -> [(a,b)] -> Maybe b
81 | linSearch _ [] = Nothing
82 | linSearch k ((a,b):xs) =
83 | if a == k
84 | then Just b
85 | else linSearch k xs
86 |
87 | -- Binary Search
88 | binSearch :: (Ord a) => a -> BinTree (a,b) -> Maybe b
89 | binSearch _ Leaf = Nothing
90 | binSearch k (Node (a,b) l r)
91 | | k == a = Just b
92 | | k > a = binSearch k r
93 | | k < a = binSearch k l
94 |
95 | -- Insert (for Binary Tree)
96 |
97 | insert :: Ord a => (a,b) -> BinTree(a,b) -> BinTree(a,b)
98 | insert pair Leaf = Node pair Leaf Leaf
99 | insert newPair@(key,v) (Node oldPair@(a,_) l r)
100 | | key == a = Node (key,v) l r
101 | | key > a = Node oldPair l (insert newPair r)
102 | | key < a = Node oldPair (insert newPair l) r
103 |
104 | -- a O(n) version of inorder function (the earlier definition is O(n²))
105 | g :: BinTree a -> [a] -> [a]
106 | g Leaf ks = ks
107 | g (Node x l r) ks = g l (x : g r ks)
108 |
109 | inorder' :: BinTree a -> [a]
110 | inorder' t = g t []
111 |
112 | -- auxiliary functions
113 | binTreeIntToBinTree :: BinTreeInt -> BinTree Int
114 | binTreeIntToBinTree LeafInt = Leaf
115 | binTreeIntToBinTree (NodeInt a l r) =
116 | Node a (binTreeIntToBinTree l) (binTreeIntToBinTree r)
117 |
--------------------------------------------------------------------------------
/src/03-recursion/notes.hs:
--------------------------------------------------------------------------------
1 | {-- RECURSION --}
2 |
3 | -- Recursion is a self referential style of definitions commonly used
4 | -- in both mathematics and computer science.
5 |
6 | -- Let's write some examples of recursive functions definitions
7 | -- in Haskell
8 |
9 | factorial :: Int -> Int
10 | factorial 0 = 1
11 | factorial n = n * factorial (n-1)
12 |
13 |
14 | -- A template for recursion over lists
15 | {--
16 | f :: [a] -> `type of result`
17 | f [] = `result for empty list`
18 | f (x:xs) = `result defined using (f xs) and x`
19 | --}
20 |
21 | length' :: [a] -> Int
22 | length' [] = 0
23 | length' (x:xs) = 1 + length' xs
24 |
25 |
26 | {-- Hand evaluation of length function
27 |
28 |
29 | length [1,2,3]
30 | = 1 + length [2,3]
31 | = 1 + (1 + length [3])
32 | = 1 + (1 + (1 + length []))
33 | = 1 + (1 + (1 + 0))
34 | = 0
35 |
36 |
37 | --}
38 |
39 |
40 | sum' :: Num a => [a] -> a
41 | sum' [] = 0
42 | sum' (x:xs) = x + sum' xs
43 |
44 |
45 | {-- Hand evaluation of sum function
46 |
47 | sum [1,2,3]
48 | = 1 + sum [2,3]
49 | = 1 + (2 + sum[3])
50 | = 1 + (2 + (3 + sum []))
51 | = 1 + (2 + (3 + 0))
52 | = 6
53 |
54 |
55 | --}
56 |
57 |
58 | append :: [a] -> [a] -> [a]
59 | append [] ys = ys
60 | append (x:xs) ys = x : (append xs ys)
61 |
62 |
63 | {-- Hand evaluation of function append
64 |
65 | append [1,2,3] [4,5,6]
66 | = 1 : (append [2,3] [4,5,6])
67 | = 1 : 2 : (append [3] [4,5,6])
68 | = 1 : 2 : 3 (append [] [4,5,6])
69 | = 1 : 2 : 3 : [4,5,6]
70 | = 1 : 2 : [3,4,5,6]
71 | = 1 : [2,3,4,5,6]
72 | = [1,2,3,4,5,6]
73 | --}
74 |
75 |
76 | zip' :: [a] -> [b] -> [(a,b)]
77 | zip' [] _ = []
78 | zip' _ [] = []
79 | zip' (x:xs) (y:ys) = (x,y) : zip xs ys
80 |
81 | {-- Hand evaluation of zip function
82 |
83 | zip [1,2,3,4] ['a','b','c']
84 | = (1,'a') : zip [2,3,4] ['b','c']
85 | = (1,'a') : (2, 'b') : zip [3,4] ['c']
86 | = (1, 'a') : (2, 'b') : (3, 'c') : zip [4]
87 | = (1, 'a') : (2, 'b') : (3, 'c') = []
88 | = [(1, 'a'), (2, 'b'), (3, 'c')]
89 | --}
90 |
91 |
92 | concat' :: [[a]] -> [a]
93 | concat' [] = []
94 | concat' (xs:xss) = append xs $ concat xss
95 |
96 | {-- Hand evaluation of the concat function
97 |
98 | concat' [[1], [2,3], [4,5,6]]
99 | = append [1] $ concat [[2,3],[4,5,6]]
100 | = append [1] $ append [2,3] $ concat [[4,5,6]]
101 | = append [1] $ append [2,3] $ append [4,5,6] $ concat []
102 | = append [1] $ append [2,3] $ append [4,5,6] []
103 | = append [1] $ append [2,3] [4,5,6]
104 | = append [1] [2,3,4,5,6]
105 | = [1,2,3,4,5,6]
106 | --}
107 |
108 |
109 | quicksort :: Ord a => [a] -> [a]
110 | quicksort [] = []
111 | quicksort (pivot:xs) =
112 | quicksort [y | y <- xs, y < pivot]
113 | ++ [pivot]
114 | ++ quicksort [y | y <- xs, y >= pivot]
115 |
116 |
117 | {-- Hand evaluation of the quicksort
118 |
119 | quicksort [3,8,5,2]
120 | = quicksort [2] ++ [3] ++ quicksort [8,5]
121 | = (quicksort [] ++ [2] ++ quicksort []) ++ [3] ++ quicksort [8,5]
122 | = ([] ++ [2] ++ []) ++ [3] ++ (quicksort [5] ++ [8] ++ quicksort [])
123 | = [2] ++ [3] ++ ((quicksort [] ++ [5] ++ quicksort []) ++ [8] ++ [])
124 | = [2,3] ++ (([] ++ [5] ++ []) ++ [8])
125 | = [2,3] ++ ([5] ++ [8])
126 | = [2,3] ++ [5,8]
127 | = [2,3,5,8]
128 | --}
129 |
130 |
131 | -- Higher Order Recursive Functions
132 |
133 |
134 | map' :: (a -> b) -> [a] -> [b]
135 | map' _ [] = []
136 | map' f (x:xs) = f x : map f xs
137 |
138 |
139 | {-- Hand evaluation of map function
140 |
141 | map (*5) [1,2,3]
142 | = 1 * 5 : map (*5) [2,3]
143 | = 5 : (2*5 : map (*5) [3])
144 | = 5 : 10 : 3 * 5 : map (* 5) []
145 | = 5 : 10 : 15 : []
146 | = [5,10,15]
147 |
148 | --}
149 |
150 | foldr' :: (a -> a -> a) -> a -> [a] -> a
151 | foldr' _ z [] = z
152 | foldr' f z (x:xs) = f x $ foldr' f z xs
153 |
154 | foldl' :: (a -> a -> a) -> a -> [a] -> a
155 | foldl' _ z [] = z
156 | foldl' f z (x:xs) = foldl' f (f z x) xs
157 |
158 | sum'' :: (Num a) => [a] -> a
159 | sum'' xs = foldr' (+) 0 xs
160 |
161 |
162 | main = print $ sum'' [1,2,3]
163 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/functions.hs:
--------------------------------------------------------------------------------
1 | {--
2 |
3 | This file explain the basic function to do:
4 |
5 | * type declaration
6 | * pattern matching
7 | * function definition
8 | * function composition
9 |
10 | --}
11 |
12 | -- :: factorial function
13 | fat :: Integer -> Integer
14 | fat 0 = 1
15 | fat n | n > 0 = n * fat (n - 1)
16 |
17 | -- :: fibonacci function
18 |
19 | -- | domain and contra-domain declaration
20 | fib :: Integer -> Integer
21 | -- | pattern matching
22 | fib n | n <= 1 = 1
23 | -- | formal definition of fib function
24 | fib n | n > 1 = fib(n - 1) + fib(n - 2)
25 |
26 | -- | function composition
27 | -- is just like fatfib = fat(fib(x))
28 | fatfib :: Integer -> Integer
29 | fatfib = fat . fib
30 |
31 |
32 | -- :: Function types
33 | -- f :: a -> b
34 | -- The function argument has the type a and result the type b
35 | -- For example, some of the Haskell functions that we have already seen have the following types:
36 | -- sqrt :: Double -> Double
37 | -- max :: Integer -> Integer -> Integer
38 | -- not :: Bool -> Bool
39 | -- toUpper :: Char -> Char
40 |
41 | -- :: Operators and Functions
42 | -- When we are dealing with operators, we just put parenthesis around it
43 | -- to specify at it. Operators are just functions with infix arguments.
44 | -- An another way to do 3+2 is calling (+) 3 2, the two statements will result
45 | -- in 6.
46 | -- We can use any function as operator just using a back-quote on them.
47 | -- max 2 3 => 3 is equal to 2 `max` 3 => 3
48 |
49 | m = max 2 3
50 | m' = 2 `max` 3
51 | m'' = m == m'
52 |
53 | -- :: Function Definitions
54 | -- We can define new functions giving the type declaration followed by the
55 | -- defining equation.
56 | -- function_name :: arg1Type -> arg2Type -> ... -> argTypen -> resultType
57 | -- function_name arg1 arg2 arg3 = exp using the arguments
58 |
59 | square :: Integer -> Integer
60 | square x = x * x
61 | -- square 2 => 4
62 |
63 |
64 | -- :: Pattern Matching
65 | -- If the argument on the left-hand side is a constant,
66 | -- then the right-hand will be used only if the function is applied
67 | -- to that value.
68 | -- This makes it possible for a function definition to consist of several
69 | -- defining equations.
70 |
71 | f :: Integer -> String
72 | f 1 = "one"
73 | f 2 = "two"
74 | f 3 = "three"
75 | f n = show n
76 |
77 | isThree :: Int -> Bool
78 | isThree 3 = True
79 | isThree x = False
80 |
81 | nor :: Bool -> Bool -> Bool
82 | nor False False = True
83 | nor a b = False
84 |
85 | first :: (a, b) -> a
86 | first (x,y) = x
87 |
88 | second :: (a,b) -> b
89 | second (x,y) = y
90 |
91 | isEmpty :: [a] -> Bool
92 | isEmpty [] = True
93 | isEmpty (x:xs) = False
94 |
95 | -- guards are indicated by pipes that follow a function's names
96 | -- and its parameters. A more powerful way of pattern matching
97 | -- using multiple conditions
98 | bmiTell :: (RealFloat a) => a -> a -> String
99 | bmiTell weight height
100 | | weight / height ^ 2 <= 18.5 = "You're underweight, you emo, you!"
101 | | weight / height ^ 2 <= 25.0 = "You're supposedly normal. Pfft, i bet you are ugly!"
102 | | weight / height ^ 2 <= 30.0 = "You're fat! Lose some weight, fatty!"
103 | | otherwise = "You're a whale, congratulations!"
104 |
105 | max' :: (Ord a) => a -> a -> a
106 | max' a b
107 | | a > b = a
108 | | otherwise = b
109 |
110 |
111 | -- where bindings
112 | initials :: String -> String -> String
113 | initials firstname lastname = [f] ++ ". " ++ [l] ++ "."
114 | where (f:_) = firstname
115 | (l:_) = lastname
116 |
117 | -- let bindings
118 | cylinder :: (RealFloat a) => a -> a -> a
119 | cylinder r h =
120 | let sideArea = 2 * pi * r * h
121 | topArea = pi * r ^ 2
122 | in sideArea + 2 * topArea
123 |
124 | -- case expressions
125 | head' :: [a] -> a
126 | head' xs = case xs of [] -> error "No head for empty lists!"
127 | (x:_) -> x
128 |
129 | describeList :: [a] -> String
130 | describeList xs = "The list is " ++ case xs of [] -> "empty."
131 | [x] -> "a singleton list."
132 | xs -> "a longer list"
133 |
134 | -- alternative version using where
135 |
136 | describeList' xs = "The list is " ++ what xs
137 | where what [] = "empty."
138 | what [x] = "a singleton"
139 | what xs = "a longer list"
140 |
141 |
142 | f' x = case x of 10 -> 10
143 | x -> x + 1
144 |
--------------------------------------------------------------------------------
/src/05-trees/Exercises.hs:
--------------------------------------------------------------------------------
1 | {-- EXERCISES --}
2 |
3 | import Notes
4 | ( BinTreeInt(LeafInt, NodeInt)
5 | , BinTree(Leaf, Node)
6 | , inorder
7 | , height
8 | )
9 |
10 | import TreePrinter
11 |
12 | -- Exercise 1
13 | -- Define a Haskell datatype Tree1 for a tree that contains a
14 | -- character and an integer in each node, along with exactly three
15 | -- subtrees.
16 |
17 | data Tree1 = Leaf1 | Node1 Integer Char Tree1 Tree1 Tree1
18 | deriving Show
19 |
20 |
21 | -- Exercise 2
22 | -- Define a Haskell datatype Tree2 for a free that contains an integer
23 | -- in each node, and that allows each node to have any number of subtrees
24 |
25 | data Tree2 = Leaf2 | Node2 Integer [Tree2]
26 | deriving Show
27 |
28 |
29 | -- Exercise 3
30 | -- Calculate the inorder traversal of tree3
31 | tree3 :: BinTreeInt
32 | tree3 = NodeInt 4
33 | (NodeInt 2
34 | (NodeInt 1 LeafInt LeafInt)
35 | (NodeInt 3 LeafInt LeafInt))
36 | (NodeInt 7
37 | (NodeInt 5
38 | LeafInt
39 | (NodeInt 6 LeafInt LeafInt))
40 | (NodeInt 8 LeafInt LeafInt))
41 |
42 | inorderBinTreeInt :: BinTreeInt -> [Int]
43 | inorderBinTreeInt LeafInt = []
44 | inorderBinTreeInt (NodeInt a l r ) =
45 | inorderBinTreeInt l ++ [a] ++ inorderBinTreeInt r
46 |
47 | tree3inorder = inorderBinTreeInt tree3
48 | -- [1,2,3,4,5,6,7,8]
49 |
50 | -- Exercise 4.
51 | -- Suppose that a tree has type BinTree a, and we have a function
52 | -- f :: a -> b. Write a new traversal function:
53 | inorderf :: (a->b) -> BinTree a -> [b]
54 | -- that traverses the tree using inorder, but it applies f to the
55 | -- data value in each node before placing the result in the list.
56 | -- For example, inorder tree6 produces [1,2,3,4,5,6,7] but
57 | -- inorderf (2*) tree6 produces [2,4,6,8,10,12,14]
58 |
59 | inorderf _ Leaf = []
60 | inorderf f (Node a l r) =
61 | inorderf f l ++ [f a] ++ inorderf f r
62 |
63 | inorderf' :: (a -> b) -> BinTree a -> [b]
64 | inorderf' f t = map f $ inorder t
65 |
66 | -- Exercise 5
67 | -- Define two trees of size seven, one with the largest possible
68 | -- height and the other with the smallest possible height
69 |
70 | -- height max => 7
71 | sevenTreeHuge :: BinTree Int
72 | sevenTreeHuge = Node 1
73 | Leaf
74 | (Node 2
75 | Leaf
76 | (Node 3
77 | Leaf
78 | (Node 4
79 | Leaf
80 | (Node 5
81 | Leaf
82 | (Node 6
83 | Leaf
84 | (Node 7 Leaf Leaf))))))
85 |
86 | -- smallest height -> 3 =~ sqrt(7)
87 | sevenTreeBalanced :: BinTree Int
88 | sevenTreeBalanced = Node 1
89 | (Node 2
90 | (Node 4 Leaf Leaf )
91 | (Node 6 Leaf Leaf))
92 | (Node 3
93 | (Node 5 Leaf Leaf)
94 | (Node 7 Leaf Leaf))
95 |
96 | -- Exercise 6
97 | -- Suppose that the last equation of the function balanced
98 | -- were changed to the following:
99 | -- balanced (Node x t1 t2) = balanced t1 && balanced t2
100 | -- Give an example showing that the modified function returns
101 | -- True for an unbalanced tree
102 |
103 | unbalancedTree = Node 1
104 | Leaf
105 | (Node 2 Leaf Leaf)
106 |
107 | {-- Hand written evaluation
108 |
109 | balanced unbalancedTree
110 | balanced (Node 1 l r)
111 | = balanced l && balanced r
112 | = balanced Leaf && balanced (Node 2 Leaf Leaf)
113 | = True && balanced Leaf && balanced Leaf
114 | = True && True && True
115 | = True
116 |
117 | --}
118 |
119 | -- Exercise 7
120 | -- Suppose that the last equation of the function balanced
121 | -- were changed to the following:
122 | -- balanced (Node x t1 t2) = height t1 == height t2
123 | -- Give an example showing that the modified function
124 | -- returns True for an unbalanced Tree.
125 |
126 | {-- EXAMPLE
127 | 1
128 | / \
129 | 2 3
130 | / \
131 | 4 5
132 |
133 | --}
134 |
135 | unbalancedTree' = Node 1
136 | (Node 2
137 | Leaf
138 | (Node 4 Leaf Leaf))
139 | (Node 3
140 | Leaf
141 | (Node 5 Leaf Leaf))
142 | {-- Hand written evaluation
143 |
144 | balanced unbalancedTree'
145 | balanced (Node 1 l r)
146 | = height l == height r
147 | = 2 == 2
148 | = True
149 |
150 | --}
151 |
152 | -- Exercise 8
153 | -- Define a function mapTree that takes a function and applies
154 | -- it to every node in the tree, returning a new tree of results.
155 | -- The type should be:
156 | mapTree :: (a -> b) -> BinTree a -> BinTree b
157 | -- This function is analogous to map, which operators over lists.
158 |
159 | mapTree f Leaf = Leaf
160 | mapTree f (Node a l r) = Node (f a) (mapTree f l) (mapTree f r)
161 |
162 | -- Exercise 9
163 | -- Write concatTree, a function that takes a tree of lists
164 | -- a function that takes a tree of lists and concatenates
165 | -- the lists in order from left to right. For example,
166 | -- concatTree (Node [2] (Node [3,4] Leaf Leaf)
167 | -- (Node [5] Leaf Leaf))
168 | -- ==> [3,4,2,5]
169 |
170 | concatTree :: BinTree [a] -> [a]
171 | concatTree Leaf = []
172 | concatTree (Node xs l r) = concatTree l ++ xs ++ concatTree r
173 |
174 | -- Exercise 10
175 | -- Write zipTree, a functino that takes two trees and pairs each
176 | -- of the corresponding elements in a list. Your function should
177 | -- return Nothing if the two trees do not have the same shape.
178 | -- For example
179 |
180 | sameShape :: BinTree a -> BinTree b -> Bool
181 | sameShape Leaf Leaf = True
182 | sameShape (Node _ l1 r1) (Node _ l2 r2) =
183 | sameHeight l1 l2 && sameHeight r1 r2 && sameShape l1 l2 && sameShape r1 r2
184 | where sameHeight l r = height l == height r
185 |
186 | zipTree :: BinTree a -> BinTree b -> Maybe [(a,b)]
187 | zipTree t1 t2
188 | | sameShape t1 t2 = Just $ zip (inorder t1) (inorder t2)
189 | | otherwise = Nothing
190 |
191 | -- Exercise 11. Write zipWithTree, a function that is like zipWith
192 | -- except that it takes trees instead of lists. The first argument is
193 | -- a function of type (a->b->c) the second argument is a tree with elements
194 | -- of type a and the third argument is a tree with elements of type b.
195 | -- The function returns a list with type [c]
196 |
197 | -- IN THIS VERSIONS IS USED THE MAYBE MONAD BECAUSE... YES!
198 | -- Why not use monads after all?
199 | -- Monads ARE MONADS (most precise definition known)
200 |
201 | zipWithTree :: (a -> b -> c) -> BinTree a -> BinTree b -> Maybe [c]
202 | zipWithTree f t1 t2 = let z = zipTree t1 t2
203 | in zipMaybe z
204 | where zipMaybe Nothing = Nothing
205 | zipMaybe (Just xs) = Just [f a b | (a,b) <- xs]
206 |
207 | -- Exercise 12. Write appendTree, a function that takes a binary tree and a
208 | -- list, and appends the contents of the tree (traversed from left to right) to
209 | -- the front of the list. For example,
210 | -- appendTree (BinNode 2 (BinNode 1 BinLeaf BinLeaf)
211 | -- (BinNode 3 BinLeaf BinLeaf))
212 | -- [4,5]
213 | -- evaluates to [1,2,3,4,5]. Try to find an efficient solution that minimises
214 | -- recopying.
215 |
216 | appendTree :: BinTree a -> [a] -> [a]
217 | appendTree Leaf xs = xs
218 | appendTree (Node x l r) xs = appendTree l (x : appendTree r xs)
219 | -- this is the same definition as g from inorder' on Notes.hs
220 | -- the partial function to write a inorder more efficiently
221 |
--------------------------------------------------------------------------------
/src/03-recursion/exercises.hs:
--------------------------------------------------------------------------------
1 | {-- Exercises --}
2 |
3 | -- Exercise 1
4 | -- Write a recursive function copy :: [a] -> [a] that copies
5 | -- its list argument. For example, copy [2] => 2.
6 |
7 | copy :: [a] -> [a]
8 | copy [] = []
9 | copy (x:xs) = x : copy xs
10 |
11 | -- Exercise 2
12 | -- write a function inverse that takes a list of pairs and
13 | -- swaps the pair elements. For example,
14 | -- inverse [(1,2),(3,4)] => [(2,1),(4,3)]
15 |
16 | inverse :: [(a,b)] -> [(b,a)]
17 | inverse [] = []
18 | inverse (x:xs) = swap x : inverse xs
19 | where swap (a,b) = (b,a)
20 |
21 | -- Exercise 3
22 | -- Write a function
23 | merge :: Ord a => [a] -> [a] -> [a]
24 | -- which takes two sorted lists and returns a sorted list
25 | -- containing the elements of each
26 | -- merge [1,2,3] [4,5,6] => [1,2,3,4,5,6]
27 | merge xs [] = xs
28 | merge [] ys = ys
29 | merge (x:xs) (y:ys)
30 | | x <= y = x:merge xs (y:ys)
31 | | otherwise = y:merge (x:xs) ys
32 |
33 | -- Hand evaluation of merge
34 | {--
35 |
36 | merge [3,4] [5,6]
37 | = 3 : (merge [4] [5,6])
38 | = 3 : 4 : (merge [] [5,6])
39 | = 3 : 4 : [5,6]
40 | = [3,4,5,6]
41 |
42 | --}
43 |
44 | -- Exericse 4
45 | -- Write (!!), a function that takes a natural number n
46 | -- and a list and selects the nth element of the list. List elements
47 | -- are indexed from 0, not 1, and since the type of the incoming number
48 | -- does not prevent it from being out of range, the result should be a Maybe
49 | -- type
50 |
51 | nth :: (Integral n, Eq a) => [a] -> n -> Maybe a
52 | nth [] _ = Nothing
53 | nth (x:_) 0 = Just x
54 | nth (_:xs) n = nth xs $ n - 1
55 |
56 | -- Exercise 5
57 | -- Write a function lookup that takes a value and a list
58 | -- of pairs, and returns the second element of the pair that
59 | -- has the value as its first element. Use a Maybe type
60 | -- to indicate wheter the lookup succeded.
61 | -- For example
62 | --
63 | -- lookup 5 [(1,2), (5,3)] => Just 3
64 | -- lookup 6 [(1,2), (5,3)] => Nothing
65 |
66 | lookup' :: (Eq a) => a -> [(a,b)] -> Maybe b
67 | lookup' _ [] = Nothing
68 | lookup' x ((a,b):xs)
69 | | x == a = Just b
70 | | otherwise = lookup x xs
71 |
72 | -- Exercise 6
73 | -- Write a function that counts the number of times
74 | -- an element appears in a list
75 | count' :: (Eq a) => a -> [a] -> Int
76 | count' _ [] = 0
77 | count' e (x:xs)
78 | | e == x = 1 + count' e xs
79 | | otherwise = count' e xs
80 |
81 | -- Exercise 7
82 | -- Write a function that takes a value e and a list of
83 | -- values xs and remove all occurrences of e from xs
84 |
85 | remove :: (Eq a) => a -> [a] -> [a]
86 | remove _ [] = []
87 | remove e (x:xs)
88 | | e == x = remove e xs
89 | | otherwise = x : remove e xs
90 |
91 |
92 | -- Exericse 8
93 | -- Write a function
94 | -- f :: [a] -> [a]
95 | -- that removes alternating elements of its lists arguments,
96 | -- starting with the first one. For example:
97 | -- f [1,2,3,4,5,6,7] => [2,4,6]
98 | alternate :: [a] -> [a]
99 | alternate [] = []
100 | alternate (_:y:xs) = y:alternate xs
101 | alternate (_:xs) = xs
102 |
103 | -- Exercise 9
104 | -- Write a function
105 | extract :: [Maybe a] -> [a]
106 | -- that takes a list of Maybe values and return
107 | -- the elements they contain. For example,
108 | -- extract [Just 3, Nothing, Just 7]
109 | extract [] = []
110 | extract (Nothing:xs) = extract xs
111 | extract (Just a:xs) = a : extract xs
112 |
113 |
114 | -- Exercise 10
115 | -- Write a function
116 | -- f :: String -> String -> Maybe Int
117 | -- that takes two strings. If the second string appears
118 | -- within the first, it return the index identifying where
119 | -- it starts. Indexes starts from 0. For example,
120 | -- f "abcde" "bc" => Just 1
121 | -- f "abcde" "fg" => Nothing
122 |
123 |
124 | find :: String -> String -> Maybe Int
125 | find _ [] = Nothing
126 | find [] _ = Nothing
127 | find str@(_:xs) substr
128 | | str `startsWith` substr = Just 0
129 | | otherwise = addMaybe $ find xs substr
130 | where addMaybe x = case x of Nothing -> Nothing
131 | Just v -> Just (v + 1)
132 | startsWith [] [] = True
133 | startsWith [] _ = False
134 | startsWith _ [] = True
135 | startsWith (a:as) (b:bs) = and $ (a == b):[startsWith as bs]
136 |
137 | -- Exercise 11
138 | -- Write foldrWith a function that behaves like foldr except
139 | -- that it takes a function of three arguments and two lists
140 | foldrWith :: (a -> b -> c -> c) -> c -> [a] -> [b] -> c
141 | foldrWith _ z [] _ = z
142 | foldrWith _ z _ [] = z
143 | foldrWith f z (x:xs) (y:ys) = f x y $ foldrWith f z xs ys
144 |
145 | -- Exercise 12
146 | -- Using foldr, write a function mappend such that
147 | -- mappend f xs = concat (map f xs)
148 |
149 | mappend' :: ([a] -> [b]) -> [[a]] -> [b]
150 | mappend' f xs = foldr ((++) . f) [] xs
151 |
152 | -- Exercise 13
153 | -- Write removeDuplicates, a function that takes a list and remove
154 | -- all of its duplicate elements.
155 |
156 | removeDuplicates :: (Eq a) => [a] -> [a]
157 | removeDuplicates [] = []
158 | removeDuplicates (x:xs) = x: removeDuplicates [k | k <- xs, x /= k]
159 |
160 |
161 | -- Exercise 14
162 | -- Write a recursive function that takes a value and a list of
163 | -- of values and returns True if the value is in the list and
164 | -- False otherwise.
165 |
166 | elem' :: (Eq a) => a -> [a] -> Bool
167 | elem' _ [] = False
168 | elem' e (x:xs)
169 | | e == x = True
170 | | otherwise = elem' e xs
171 |
172 |
173 | -- Exercise 15
174 | -- Write a function that takes two lists, and returns a list of values that appear in both lists.
175 | -- The function should have type:
176 | intersection :: Eq a => [a] -> [a] -> [a]
177 | -- (This is one way to implement the intersection operation on sets; see Chapter 8)
178 |
179 | intersection [] _ = []
180 | intersection _ [] = []
181 | intersection (x:xs) ys
182 | | x `elem` ys = x : intersection xs ys
183 | | otherwise = intersection xs ys
184 |
185 |
186 | -- Exercise 16
187 | -- Write a function that takes two lists, and returns True if all the elements
188 | -- of the first list also occur in the other. The function should have
189 | -- type:
190 | isSubset :: Eq a => [a] -> [a] -> Bool
191 | -- (This is one way to determine wheter one set is a subset of another; see Chapter 8)
192 |
193 | isSubset xs ys = intersection xs ys == xs
194 |
195 | -- Exercise 17
196 | -- Write a recursive function that determines wheter a list is sorted
197 | isSorted :: (Ord a) => [a] -> Bool
198 | isSorted [] = True
199 | isSorted [x] = True
200 | isSorted (x:xs) = x <= head xs && isSorted xs
201 |
202 | -- Exercise 18
203 | -- Show that the definition of factorial using foldr always produces
204 | -- the same result as the recursive definition given in the previous section.
205 |
206 | factorialr :: (Integral n) => n -> n
207 | factorialr 0 = 1
208 | factorialr n = n * factorialr(n - 1)
209 |
210 |
211 | factorialf :: (Integral n) => n -> n
212 | factorialf n = foldr (*) 1 [1..n]
213 |
214 | {-- Hand evaluation of factorialr
215 |
216 | factorialr 4
217 | = 4 * factorialr 3
218 | = 4 * (3 * factorialr 2)
219 | = 4 * (3 * (2 * factorialr 1))
220 | = 4 * (3 * (2 * (1 * factorialr 0)))
221 | = 4 * (3 * (2 * (1 * 1)))
222 | = 4 * (3 * 2)
223 | = 4 * 6
224 | = 24
225 |
226 | --}
227 |
228 | {-- Hand evaluation of factorialf
229 | factorialf 4 <=> foldr (*) 1 [1,2,3,4]
230 | = 1 * foldr (*) 1 [2,3,4]
231 | = 1 * (2 * foldr (*) 1 [3,4])
232 | = 1 * (2 * (3 * foldr (*) 1 [4]))
233 | = 1 * (2 * (3 * (4 * foldr (*) 1 [])))
234 | = 1 * (2 * (3 * (4 * 1)))
235 | = 1 * (2 * 12)
236 | = 24
237 |
238 | --}
239 |
240 |
241 | -- Exercise 19
242 | -- Using recursion, define last, a function that takes a list and
243 | -- returns a Maybe type that is Nothing if the list is empty
244 |
245 | last' :: [a] -> Maybe a
246 | last' [] = Nothing
247 | last' [x] = Just x
248 | last' (_:xs) = last' xs
249 |
250 | -- Exercise 20
251 | -- Using recursion, write two functions that expect a string containing
252 | -- a number that contains a decimal point (for example, 23.455)
253 | -- The first function returns the whole part of the number (i.e., the part
254 | -- to the left of the decimal point). The second function returns the fractional part (the part of the right of the decimal point).
255 |
256 | -- split :: String -> (String, String)
257 |
258 |
259 | whole :: String -> String
260 | whole [] = []
261 | whole ('.':_) = []
262 | whole (x:xs) = x : whole xs
263 |
264 | fractional :: String -> String
265 | fractional [] = []
266 | fractional (_:'.':xs) = xs
267 | fractional (x:xs) = fractional xs
268 |
269 | -- test zone
270 | testExercise :: (Integer, Bool) -> String
271 | testExercise (n, solved) = "Exercise " ++ show n ++ ": "
272 | ++ if solved then "Solved" else "Incorrect"
273 |
274 |
275 |
276 | tests :: [(Integer, Bool)]
277 | tests = [(1, [1,2,3] == copy [1,2,3]),
278 | (2, [(2,1),(3,2),(4,3)] == inverse [(1,2),(2,3),(3,4)]),
279 | (3, [1,2,3,3,4,5] == merge [1,2,3] [3,4,5]),
280 | (4, Just 5 == nth [1,2,3,4,5] 4),
281 | (5, Just 3 == lookup' 5 [(1,2), (5,3)]),
282 | (6, 3 == count' 3 [3,3,3]),
283 | (7, [1,2,3] == remove 4 [1,2,3,4,4,4]),
284 | (8, [2,4,6] == alternate [1,2,3,4,5,6,7]),
285 | (9, [3,7] == extract [Just 3, Nothing, Just 7]),
286 | (10, Just 0 == find "manel" "man"),
287 | (11, 12 == foldrWith (\x y z -> x + y + z) 0 [1,2,3] [1,2,3]),
288 | (12, [1,2,3,4,5,6] == mappend' (map (+1)) [[0,1,2], [3,4,5]]),
289 | (13, [1,2,3] == removeDuplicates [1,1,2,2,3,3]),
290 | (14, True == elem' 1 [0,0,1]),
291 | (15, [1,2,3] == intersection [0,1,2,3,4] [-1,1,2,3,5]),
292 | (16, isSubset [1, 2, 3] [1, 2, 3, 4]),
293 | (17, isSorted [0, 1, 2, 3, 4, 5]),
294 | (18, factorialr 10 == factorialf 10),
295 | (19, Just 3 == last' [1,2,3]),
296 | (20, "321" == fractional "123.321" && "123" == whole "123.321")]
297 |
298 | main :: IO()
299 | main = mapM_ (putStrLn . testExercise) tests
300 |
--------------------------------------------------------------------------------
/src/01-introduction-to-haskell/exercises.hs:
--------------------------------------------------------------------------------
1 | {-- A Compilation of the Exercises of Chapter 1
2 |
3 | INTRODUCTION TO HASKELL
4 |
5 | --}
6 |
7 |
8 | {-- Operators, Functions and basic Types (Lists, Strings, Int, Bool, Tuple) --}
9 | -- Exercise 3.
10 | -- Write a function that takes a character and returns True
11 | -- if the character is 'a' and False otherwise
12 |
13 | ex3 :: Char -> Bool
14 | ex3 'a' = True
15 | ex3 c = False
16 |
17 | -- Exercise 4.
18 | -- Write a function that takes a string and returns True if
19 | -- the string is "hello" and false otherwise. This can be done
20 | -- by specifying each element of the string in the list pattern (e.g. 'h':'i':[])
21 |
22 | ex4 :: String -> Bool
23 | ex4 "hello" = True
24 | ex4 s = False
25 |
26 | -- Exercise 5.
27 | -- Write a function that takes a string and removes a leading space if it exists.
28 |
29 | ex5 :: String -> String
30 |
31 | ex5 (' ':x) = x
32 | ex5 x = x
33 |
34 |
35 | -- Exercise 6
36 | -- Suppose a program has read in a list of numbers of type Int.
37 | -- Each number is intended to represent a Boolean value, where 0
38 | -- Means False, 1 means True and any other number constitutes
39 | -- invalid input. Write a function convert :: [Int] -> [Bool]
40 | -- that converts a list of numbers to the corresponding Booleans
41 | convert :: [Int] -> [Bool]
42 | convert list = map bool list
43 | where bool n = case n of 0 -> False
44 | 1 -> True
45 |
46 | -- Exercise 7
47 | -- Write a function member0 :: String -> Bool that takes a list
48 | -- of Char values (i.e. a String), and returns True if at least one
49 | -- of the characters is '0' and False otherwise.
50 |
51 | member0 :: String -> Bool
52 | member0 s = or $ map (== '0') s
53 |
54 | -- Exercise 8
55 | -- Expand the following application
56 | -- foldr max 0 [1,5,3]
57 |
58 | -- Answer: max 1 (max 5 (max 3 0))
59 |
60 | -- Exercise 9
61 | -- Write a function that takes two lists of type [Maybe Int] and
62 | -- examines the pair of list heads before looking at the rest of the lists.
63 | -- It returns a list in which the Ints of each pair have been added if both
64 | -- are of the form Just n, preserving any Just n value otherwise. For example,
65 | -- addJust [Just 2, Nothing, Just 3] [Nothing, Nothing, Just 5]
66 | -- => [Just 2, Nothing, Just 8]
67 |
68 | -- using zipWith
69 | addJust :: [Maybe Int] -> [Maybe Int] -> [Maybe Int]
70 | addJust u v = zipWith maybeSum u v
71 | where maybeSum Nothing y = y
72 | maybeSum x Nothing = x
73 | maybeSum (Just x) (Just y) = Just $ x + y
74 |
75 | -- using recursion
76 | addJust' :: [Maybe Int] -> [Maybe Int] -> [Maybe Int]
77 | addJust' [] _ = []
78 | addJust' _ [] = []
79 | addJust' (x:xs) (Nothing:ys) = x : addJust' xs ys
80 | addJust' (Nothing:xs) (y:ys) = y : addJust' xs ys
81 | addJust' ((Just x):xs) ((Just y):ys) = Just (x + y) : addJust' xs ys
82 |
83 |
84 | -- Exercise 10
85 | -- Define a data type that represents six different metals and automatically
86 | -- creates versions of (==) and show
87 |
88 | data Metal = Gold | Steel | Bronze | Iron
89 | | Silver | Nickel
90 | deriving (Show, Eq)
91 |
92 | -- Exercise 11
93 | -- Suppose that you have some coins that have been sorted
94 | -- into piles, each of which contains only one kind of coin.
95 | -- Define a data type that can be used to present the pile
96 | -- of coins.
97 | data Coin n = US n | BRL n | EUR n | JPZ n
98 | deriving (Show, Eq)
99 |
100 | data Pile list = Coins list
101 | deriving Show
102 |
103 |
104 | bucket :: Pile [Coin Integer]
105 | bucket = Coins $ [BRL x | x <- [1,2,5,10,25,50,100]]
106 | -- => Coins [BRL 1,BRL 2,BRL 5,BRL 10,BRL 25,BRL 50,BRL 100]
107 |
108 | -- Exercise 12
109 | -- A universal type is one in which any type can be represented.
110 | -- Each different type is identified by its own constructor, which
111 | -- serves as distinguishing tag. For example, here is a universal type
112 | -- that represents three different types of number.
113 | --
114 | -- data Number = INT Int | INTEGER Integer | FLOAT Float
115 | -- deriving (Eq, Show)
116 |
117 | data Universal = INT Int | INTEGER Integer | CHAR Char | BOOL Bool
118 | deriving (Eq, Ord, Show)
119 |
120 | -- Exercise 13
121 | -- Define a type that contains tuples of up to four elements
122 |
123 | data Tuple4 = T1 (Int) | T2 (Int, Int) | T3 (Int, Int, Int)
124 | | T4 (Int, Int, Int, Int)
125 | deriving (Eq, Show)
126 |
127 | -- Exercise 14
128 | -- The quadratic equation ax² + bx² + c = 0 has two roots given
129 | -- by the formula ... as long as the discriminant is non-negative.
130 | -- If the discriminant is negative the roots are complex.
131 | -- Define a function that finds the real solutions of the quadratic
132 | -- equation, and reports failure if they don't exists.
133 |
134 | -- Floating because sqrt only returns a float
135 | quadratic :: (Floating a, Ord a) => a -> a -> a -> Maybe (a, a)
136 | quadratic a b c
137 | | discriminant < 0 = Nothing
138 | | a == 0 = Nothing
139 | | otherwise = let x1 = ((-b) + sqrt discriminant)/(2*a)
140 | x2 = ((-b) - sqrt discriminant)/(2*a)
141 | in Just (x1,x2)
142 | where discriminant = (b ^ 2) - 4 * a * c
143 |
144 |
145 | -- Exercise 15
146 | -- Define a function
147 | -- showMaybe :: Show a => Maybe a -> String
148 | -- that takes a Maybe value and prints it
149 |
150 | showMaybe :: Show a => Maybe a -> String
151 | showMaybe (Just x) = show x
152 | showMaybe x = show x
153 |
154 | -- Exercise 16
155 | -- A bit is an integer that is either 0 or 1. A Word is a list of bits
156 | -- that represents a binary number. Here are some binary values that can be
157 | -- represented by words
158 | --
159 | -- [1, 0] => 2
160 | -- [1,0,0,1] => 9
161 | -- [1,1,1] => 7
162 | --
163 | -- We can define functions that are the Bit equivalent of or and and as
164 | -- follows:
165 | --
166 | bitOr :: Int -> Int -> Int
167 | bitOr 0 0 = 0
168 | bitOr x y = 1
169 |
170 | bitAnd :: Int -> Int -> Int
171 | bitAnd 1 1 = 1
172 | bitAnd x y = 0
173 |
174 | -- Now it is possible to take the `bitwise` and of two words as follows:
175 | -- bitwiseAnd [1,0,0] [1,0,0]
176 | -- [bitAnd 1 1, bitAnd 0 0, bitAnd 0 1]
177 | -- [1,0,0]
178 |
179 | -- bitwiseAnd [0,0,0] [1,1,0]
180 | -- [0,0,0]
181 |
182 | bitwiseAnd :: [Int] -> [Int] -> [Int]
183 | bitwiseAnd x y = zipWith bitAnd x y
184 | bitwiseOr :: [Int] -> [Int] -> [Int]
185 | bitwiseOr x y = zipWith bitOr x y
186 |
187 | -- Exercise 17
188 | -- Each of the following expressions has a type error. Change the expression so that
189 | -- the type error no longer occurs.
190 | -- [1, False] '2' ++ 'a'
191 | -- [(3, True), (False, 9)] 2 == False
192 | -- 'a' > "b" [[1], [2], [[3]]]
193 | ex17_1 = (1, False)
194 | ex17_2 = "2" ++ "a"
195 | ex17_3 = [(3, True), (9, False)]
196 | ex17_4 = 2 == 0
197 | ex17_5 = 'a' > 'b'
198 | ex17_6 = [[1],[2],[3]]
199 |
200 | -- Exercise 18
201 | -- What caused the type error in this definition and application
202 | -- f :: Num a => (a, a) -> a
203 | -- f (x,y) = x + y
204 | -- f (True,4)
205 |
206 | -- The type declaration assumes the both of elements of 2-uple must
207 | -- be in the Type class Num, however, a fun call is made with a
208 | -- heterogeneous tuple with a Bool type on the first element.
209 | -- Calling f with any (x,y) where x and y are Nums will not raise a type error
210 |
211 | -- Exercise 19
212 | -- Why does this definition produce an error when used?
213 | -- f :: Maybe a -> [a]
214 | -- f Nothing = []
215 | -- f (Just 3)
216 |
217 | -- A non-exhaustive pattern matching is defined and called.
218 | -- A f definition need be made to handle the (Just n) pattern.
219 | -- This can be fixed that way: f (Just n) = n
220 |
221 |
222 | -- Exercise 20
223 | -- Write a list comprehension that takes a list of Maybe values
224 | -- and returns a list of the Just Constructor Arguments. For example,
225 | -- [Just 3, Nothing, Just 4] => [3, 4]
226 |
227 | filterMaybe :: [Maybe Int] -> [Int]
228 | filterMaybe list = map (\(Just n) -> n) $ filter (/= Nothing) list
229 |
230 | filterMaybe' :: [Maybe Int] -> [Int]
231 | filterMaybe' list = [n x | x <- list, x /= Nothing, let n (Just v) = v]
232 |
233 |
234 | -- Exercise 21
235 | -- Using a list comprehension, write a function that takes a list
236 | -- of Int values and an Int value and returns those elements in the list
237 | -- that are greater than n
238 | filterGreaterThanN :: [Int] -> Int -> [Int]
239 | filterGreaterThanN list n = [x | x <- list, x > n]
240 |
241 |
242 | -- Exercise 22
243 | -- Write a Function
244 | f :: [Int] -> Int -> [Int]
245 | -- That takes a list of Int values and an Int and return a list of indexes at
246 | -- which that Int appears
247 | f list n = [i | (x,i) <- zip list [0..], x == n]
248 |
249 |
250 | -- Exercise 23
251 | -- Write a list comprehension that produces a list giving all of the
252 | -- positive integers that are not squares in the range 1 to 20
253 |
254 | squaresFiltered = [x | x <- [1..], not $ x^2 `elem` [1..20]]
255 | -- Be careful, infinite list.
256 |
257 |
258 | -- Exercise 24
259 | -- Write a function that uses foldr to count the number of times
260 | -- a letter occurs in a string
261 | -- count :: String -> Char -> Int
262 | count :: (Foldable t, Num a1, Eq a) => t a -> a -> a1
263 | count l x = foldr (\y acc -> if x == y then acc + 1 else 0) 0 l
264 |
265 |
266 | -- Exercise 25
267 | -- Write a function using foldr that takes a list and removes
268 | -- each instance of a given letter
269 | remove :: Foldable t => t Char -> Char -> [Char]
270 | remove l x = foldr (\y acc -> if x == y then acc else y:acc) "" l
271 |
272 | -- Exercise 26
273 | -- Using foldl, write a function
274 | rev :: [a] -> [a]
275 | -- that reverses its list argument
276 | rev l = foldl (\acc x -> x:acc) [] l
277 |
278 |
279 | -- Exercise 27
280 | -- Using foldl, write a function
281 | maybeLast :: [a] -> Maybe a
282 | -- That takes a list and returns the last element in it if there is one,
283 | -- otherwise it returns Nothing
284 |
285 | maybeLast l = foldl (\acc x -> Just x) Nothing l
286 |
--------------------------------------------------------------------------------