├── 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 | ![haskell](etc/haskell.png) 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 | ![progress](http://progressed.io/bar/27) 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 | ![exercise-1](exercise_01.jpg) 8 | ## Exercise 2 9 | ![exercise-2](exercise_02.jpg) 10 | ## Exercise 3 11 | ![exercise-3](exercise_03.jpg) 12 | ## Exercise 4 13 | ![exercise-4](exercise_04.jpg) 14 | 15 | # List Induction 16 | The real part to prove recursive programs that handles lists. 17 | 18 | ## Exercise 5 19 | ![exercise-5](exercise_05.jpg) 20 | 21 | ## Exercise 6 22 | ![exercise-6](exercise_06.jpg) 23 | 24 | ## Exercise 7 25 | ![exercise-7](exercise_07.jpg) 26 | 27 | ## Exercise 8 28 | ![exercise-8](exercise_08.jpg) 29 | 30 | ## Exercise 9 31 | ![exercise-9](exercise_09.jpg) 32 | 33 | ## Exercise 10-11 34 | ![exercise-10-11](exercise_10-11.jpg) 35 | 36 | ## Exercise 12-14 37 | ![exercise-12-14](exercise_12-14.jpg) 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 | ![exercise-16](exercise_16.jpg) 55 | 56 | ## Exercise 17-18 57 | ![exercise-17-18](exercise_17-18.jpg) 58 | 59 | ## Exercise 19 60 | ![exercise-19](exercise_19.jpg) 61 | 62 | ## Exercise 20 63 | ![exercise-20](exercise_20.jpg) 64 | 65 | ## Exercise 23 66 | ![exercise-23](exercise_23.jpg) 67 | 68 | ## Exercise 25-27 69 | ![exercise-25-27](exercise_25-27.jpg) 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 | --------------------------------------------------------------------------------