├── .gitignore ├── 01-poly.md ├── 02-poly-num.md ├── 05-pattern-syntax.md ├── 06-library-inverse.md ├── 07-cite-novel.md ├── 08-angular-dollar.md ├── 09-angular-asterisk.md ├── 10-general-composition.md ├── 11-solve-form.md ├── 12-long-addition.md ├── 13-addition-quickcheck.md ├── 14-incomplete-map.md ├── 15-list-monad.md ├── 16-comprehension-bug.md ├── 16-power-tower.md ├── 17-tower-infinity.md ├── 18-iterate-tower.md ├── 19-tower-prim.md ├── 20-tight-recursion.md ├── 21-prim-fold.md ├── 22-prim-scheme.md ├── 23-folding-functions.md ├── 24-catalans.md ├── 25-empty-functor.md ├── 26-cata-instance.md ├── 27-omega-comprehensions.md ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | cabal-dev 3 | *.o 4 | *.hi 5 | *.chi 6 | *.chs.h 7 | .virtualenv 8 | .hsenv 9 | .cabal-sandbox/ 10 | cabal.sandbox.config 11 | cabal.config 12 | -------------------------------------------------------------------------------- /01-poly.md: -------------------------------------------------------------------------------- 1 | ## Exercise 01 2 | 3 | Fix the program below. 4 | 5 | The program computes value of a complex polynomial at the given point. 6 | 7 | Polynomial is given as a list of `((Int,Int),Int)` elements, where the pair `(Int,Int)` stands for real and imaginary unit of the quotient, and the remaining `Int` represents degree. Therefore, value of the polynomial in complex point `x` is computed as the sum of `a_i*(x^t)` where `a_i` is the `i`th quotient and `t` degree. 8 | 9 | ```Haskell 10 | type Komp = (Int, Int) 11 | (+%) :: Komp -> Komp -> Komp 12 | (r1, i1) +% (r2, i2) = (r1+r2, i1+i2) 13 | 14 | (*%) :: Komp -> Komp -> Komp 15 | (r1, i1) *% (r2, i2) = (r1*r2 - i1*i2, r1*i2 + i1*r2) 16 | 17 | (^%) :: Komp -> Int -> Komp 18 | k ^% 1 = k 19 | k ^% n = (k ^% (n-1)) *% k 20 | 21 | vredKompPol :: [(Komp,Int)] -> Komp -> Komp 22 | vredKompPol ((k,s):poli) t = k*%(t^%s) +% (vredKompPol poli t) 23 | ``` 24 | 25 | `+%`, `*%` and `^%` are nothing more but operations `+`, `*` and `^` defined over complex numbers represented by the type `Komp`. 26 | 27 | The code loads fine in `ghci` but execution: 28 | 29 | Main> vredKompPol [((1,1),2),((1,1),0)] (0,0) 30 | 31 | throws an error: 32 | 33 | `ERROR - Control Stack Overflow` 34 | 35 | -------------------------------------------------------------------------------- /02-poly-num.md: -------------------------------------------------------------------------------- 1 | ## Exercise 02 2 | 3 | Rewrite [Exercise 01](01-poly.md) to use a custom `Num` instance 4 | -------------------------------------------------------------------------------- /05-pattern-syntax.md: -------------------------------------------------------------------------------- 1 | Fix errors in the code below: 2 | 3 | ```Haskell 4 | inverse :: [(a,b)] -> [(b,a)] 5 | inverse [] = [] 6 | inverse (x,y):xs = (y:x): inverse xs 7 | ``` 8 | -------------------------------------------------------------------------------- /06-library-inverse.md: -------------------------------------------------------------------------------- 1 | ## Exercise 06 2 | 3 | Reimplement [Exersise 05](05-pattern-syntax.md) using library functions. 4 | -------------------------------------------------------------------------------- /07-cite-novel.md: -------------------------------------------------------------------------------- 1 | Write `novel` and `cite` functions. 2 | 3 | ``` 4 | > novel ("Rowling", "Harry Potter", 1998) 5 | "Harry Potter (Rowling, 1998)" 6 | 7 | > cite [("author1", "book1", year1), ("author2", "book2", year2), ("author3", "book3", year3)] 8 | "book1 (author1, year1) 9 | book2 (author2, year2) 10 | book3 (author3, year3)" 11 | ``` 12 | -------------------------------------------------------------------------------- /08-angular-dollar.md: -------------------------------------------------------------------------------- 1 | ## Exercise 08 2 | 3 | Explain what `(+3) <$> (+2)` does 4 | -------------------------------------------------------------------------------- /09-angular-asterisk.md: -------------------------------------------------------------------------------- 1 | ## Exercise 09 2 | 3 | Explain what `(*) <*> (+2)` does. 4 | -------------------------------------------------------------------------------- /10-general-composition.md: -------------------------------------------------------------------------------- 1 | ## Exercise 10 2 | 3 | `<$>` from `Data.Functor` and `.` from `Control.Category` can be seen as generalizations of `.` from `Prelude`. Which of them is more general? 4 | -------------------------------------------------------------------------------- /11-solve-form.md: -------------------------------------------------------------------------------- 1 | ## Exercise 11 2 | 3 | Fix errors in the code below: 4 | 5 | ```Haskell 6 | solve :: Int -> Integer 7 | solve = undefined 8 | 9 | main = do 10 | n <- readLn 11 | forM_ [1..n] (\i -> do 12 | m <- readLn 13 | printf "Case %d: %d" i (solve m)) 14 | ``` 15 | -------------------------------------------------------------------------------- /12-long-addition.md: -------------------------------------------------------------------------------- 1 | # Exercise 12 2 | 3 | Below is terribly wrong code for long addition, where numbers are represented as lists of decimal digits: 4 | 5 | ```Haskell 6 | addLnat [x] [y] = rem (x + y) 10 : (quot (x + y) 10) : [] 7 | addLnat (x:xs) (y:ys) = (rem (x + y) 10) : w + head (addLnat xs ys) 8 | where w = quot (x + y) 10 9 | ``` 10 | Fix type errors in the code above. Find a counterexample for which the code gives wrong answer. 11 | -------------------------------------------------------------------------------- /13-addition-quickcheck.md: -------------------------------------------------------------------------------- 1 | ## Exercise 13 2 | 3 | Write a `QuickCheck` property to prove `addLnat` from [Exercise 12](12-long-addition.md) wrong. You can cheat by avoiding a full implementation of long addition. 4 | -------------------------------------------------------------------------------- /14-incomplete-map.md: -------------------------------------------------------------------------------- 1 | # Exercise 14 2 | 3 | Finish implementation of `createList` according to the specification. 4 | 5 | ```Haskell 6 | 7 | createlist l1 l2 = map (f l2) l1 8 | where f l x = undefined 9 | ``` 10 | 11 | ``` 12 | > createlist [1,2] ['a','b','c'] 13 | [[(1,'a'),(1,'b'),(1,'c')],[(2,'a'),(2,'b'),(2,'c')]] 14 | ``` 15 | 16 | -------------------------------------------------------------------------------- /15-list-monad.md: -------------------------------------------------------------------------------- 1 | # Exercise 15 2 | 3 | Implement `foo a b = concat $ createList a b`, where `createList` is from [Exercise 14](14-incomplete-map.md), using the list monad. 4 | -------------------------------------------------------------------------------- /16-comprehension-bug.md: -------------------------------------------------------------------------------- 1 | # Exercise 16 2 | 3 | ```Haskell 4 | sub 5 = return [1] 5 | sub x = 6 | do 7 | xs <- sub (x - 1) 8 | return (x:xs) 9 | 10 | f xs = [ length (sub x) | x<-xs ] 11 | ``` 12 | 13 | `sub 10` returns `10,9,8,7,6,1` but `length (sub x)` in the comprehension apparently returns 1 instead of 6. Fix the comprehension. 14 | -------------------------------------------------------------------------------- /16-power-tower.md: -------------------------------------------------------------------------------- 1 | # Exercise 16 2 | 3 | The following function doesn't compile. Fix the type error. 4 | 5 | ```Haskell 6 | tower :: Float -> Int -> Float 7 | tower x 0 = 1 8 | tower x n = x^(tower x (n-1)) 9 | ``` 10 | -------------------------------------------------------------------------------- /17-tower-infinity.md: -------------------------------------------------------------------------------- 1 | # Exercise 17 2 | 3 | `tower 5 3` from [Exercise 16](16-power-tower.md) is apparently `Infinity`. Fix the problem. 4 | -------------------------------------------------------------------------------- /18-iterate-tower.md: -------------------------------------------------------------------------------- 1 | # Exercise 18 2 | 3 | Implement `tower` from [Exercise 17](17-tower-infinity.md) non-recursively using `iterate`. 4 | -------------------------------------------------------------------------------- /19-tower-prim.md: -------------------------------------------------------------------------------- 1 | # Exercise 19 2 | 3 | Implement `tower` from [Exercise 17](17-tower-infinity.md) non-recursively using a scheme for primitive recursion: 4 | 5 | ```Haskell 6 | prim c f 0 = c 7 | prim c f n = f n (prim c f (n - 1)) 8 | ``` 9 | -------------------------------------------------------------------------------- /20-tight-recursion.md: -------------------------------------------------------------------------------- 1 | # Exercise 20 2 | 3 | ```Haskell 4 | prim c f 0 = c 5 | prim c f n = f n (prim c f (n - 1)) 6 | ``` 7 | The `prim` function passes `c` and `f` over and over despite they are loop invariants. 8 | Rewrite `prim` to use an inner function so they are kept in a closure instead. 9 | -------------------------------------------------------------------------------- /21-prim-fold.md: -------------------------------------------------------------------------------- 1 | # Exercise 21 2 | 3 | Rewrite `prim` from [Exercise 20](20-tight-recursion) non-recursively using list folds. 4 | -------------------------------------------------------------------------------- /22-prim-scheme.md: -------------------------------------------------------------------------------- 1 | # Exercise 22 2 | 3 | Rewrite `prim` from [Exercise 20](20-tight-recursion) non-recursively using `recursion-schemes` library. 4 | -------------------------------------------------------------------------------- /23-folding-functions.md: -------------------------------------------------------------------------------- 1 | # Exercise 23 2 | 3 | The following code constructs a function by list folding and then apples it to `Nothing`. 4 | Figure out what `compress` does and reimplement it without the folding trick. 5 | 6 | ```Haskell 7 | compress xs = foldr f (const []) xs Nothing 8 | where 9 | f x r a@(Just q) | x == q = r a 10 | f x r _ = x : r (Just x) 11 | ``` 12 | -------------------------------------------------------------------------------- /24-catalans.md: -------------------------------------------------------------------------------- 1 | # Exercise 24 2 | 3 | ```Haskell 4 | data Empty = Empty | Node EmptyTree EmptyTree 5 | allPossibleTrees = Empty : [Node x y | x <- allPossibleTrees, y <- allPossibleTrees] 6 | ``` 7 | 8 | The code attempts to generate an infinite list of all possible trees, sorted by number of nodes. The code 9 | seems to work, but there is a counterexample: there should be 42 trees with 5 nodes. Fix the code and write 10 | a test to ensure that the above property holds. 11 | -------------------------------------------------------------------------------- /25-empty-functor.md: -------------------------------------------------------------------------------- 1 | # Exercise 25 2 | 3 | ```Haskell 4 | data Empty = Empty | Node EmptyTree EmptyTree 5 | ``` 6 | 7 | The tree above is a fixed point of a functor. Find the functor. 8 | -------------------------------------------------------------------------------- /26-cata-instance.md: -------------------------------------------------------------------------------- 1 | # Exercise 26 2 | 3 | Using the functor from [Exercise 25](25-empty-functor.md), define the necessary 4 | instances and write a non-recursive `emptyLength :: Empty -> Integer` function that operates on 5 | the original non-fixedpoint tree using `cata` from `recursion-schemes` 6 | -------------------------------------------------------------------------------- /27-omega-comprehensions.md: -------------------------------------------------------------------------------- 1 | # Exercise 27 2 | 3 | Implement `allPossibleTrees` from [Exercise 24](24-catalans.md) using `control-monad-omega` and monad comprehensions. 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 nponeccop 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # haskell-exercises 2 | --------------------------------------------------------------------------------