Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 918df13

Browse files
committed
More chapters completed
1 parent b030f49 commit 918df13

File tree

5 files changed

+240
-2
lines changed

5 files changed

+240
-2
lines changed

‎.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vscode

‎README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
# Programming in Haskell exercices
22

3-
My solutions to the exercices provided in the book *Programming in Haskell 2nd Edition*, by Graham Hutton.
3+
My solutions to the exercices provided in the book *Programming in Haskell 2nd Edition*, by Graham Hutton.
4+
5+
## Contents
6+
7+
1. [Introduction](https://github.com/Forensor/programming-in-haskell-exercices/blob/master/src/Ch1.hs)
8+
2. [First steps](https://github.com/Forensor/programming-in-haskell-exercices/blob/master/src/Ch2.hs)
9+
3. [Types and classes](https://github.com/Forensor/programming-in-haskell-exercices/blob/master/src/Ch3.hs)
10+
4. [Defining functions](https://github.com/Forensor/programming-in-haskell-exercices/blob/master/src/Ch4.hs)
11+
5. [List comprehensions](https://github.com/Forensor/programming-in-haskell-exercices/blob/master/src/Ch5.hs)
12+
6. [Recursive functions](https://github.com/Forensor/programming-in-haskell-exercices/blob/master/src/Ch6.hs)
13+
7. [Higher-order functions](https://github.com/Forensor/programming-in-haskell-exercices/blob/master/src/Ch7.hs)

‎src/Ch5.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ count x xs = length [x' | x' <- xs, x == x']
8989

9090
calcStrLetFreq :: String -> [Float]
9191
calcStrLetFreq xs = [percent (count x (map toLower xs)) n | x <- ['a'..'z']]
92-
where n = length (filter isLetter xs)
92+
where n = length (filter isLetter xs)
9393

9494
-- Chi-square statistic, a method to compare a list of observed freqs with a list of
9595
-- expected ones.

‎src/Ch6.hs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
module Ch6 where
2+
3+
-- 1. Modify the definition of factorial function to prohibit negative arguments by
4+
-- adding a guard to the recursive case.
5+
factorial :: Int -> Int
6+
factorial 0 = 1
7+
factorial n | n < 0 = n
8+
| otherwise = n * factorial (n-1)
9+
10+
-- 2. Define sumdown :: Int -> Int that returns the sum of non-negative integers from a
11+
-- given number down to zero.
12+
sumdown :: Int -> Int
13+
sumdown 0 = 0
14+
sumdown n = n + sumdown (n-1)
15+
16+
-- 3. Definde the exponentiation operator ^ for non-negative numbers using the same
17+
-- pattern of recursion as the multiplication operator *, and show how the expression
18+
-- 2^3 is evaluated using your definition.
19+
expo :: Int -> Int -> Int
20+
expo _ 0 = 1
21+
expo n 1 = n
22+
expo n e = n * (n `expo` (e-1))
23+
-- expo 2 3 evaluates as
24+
-- 2 * (2 `expo` (2)) -> 2 * (2 * (2 `expo` (1))) -> 2 * (2 * (2)) which gives 8
25+
26+
-- 4. Define a recursive function euclid :: Int -> Int -> Int that implements Euclid's
27+
-- algorithm for calculating the greatest common divisor of two non-negative integers.
28+
euclid :: Int -> Int -> Int
29+
euclid n m | r == 0 = b
30+
| otherwise = euclid b r
31+
where
32+
(a,b) = (max n m, min n m)
33+
r = a `mod` b
34+
35+
-- 5. Using the recursive definitions given in this chapter, show how length [1,2,3],
36+
-- drop 3 [1,2,3,4,5] and init [1,2,3] are evaluated.
37+
-- length [1,2,3] -> 1 + (length [2,3]) -> 1 + (1 + (length [3])) ->
38+
-- 1 + (1 + (1 + (length []))) -> 1 + (1 + (1 + (0))) -> 3
39+
40+
-- drop 3 [1,2,3,4,5] -> drop 2 [2,3,4,5] -> drop 1 [3,4,5] -> drop 0 [4,5] -> [4,5]
41+
42+
-- init [1,2,3] -> 1 : (init [2,3]) -> 1 : (2 : (init [3])) -> 1 : (2 : ([])) -> [1,2]
43+
44+
-- 6. Define the following functions on lists using recursion:
45+
and' :: [Bool] -> Bool
46+
and' [] = True
47+
and' (False:_) = False
48+
and' (True:bs) = and' bs
49+
50+
concat' :: [[a]] -> [a]
51+
concat' [] = []
52+
concat' [xs] = xs
53+
concat' (as:bss) = as ++ concat' bss
54+
55+
replicate' :: Int -> a -> [a]
56+
replicate' 0 _ = []
57+
replicate' n x = x : replicate' (n-1) x
58+
59+
-- !!
60+
select :: [a] -> Int -> a
61+
select (x:_) 0 = x
62+
select (_:xs) n = select xs (n-1)
63+
64+
elem' :: Eq a => a -> [a] -> Bool
65+
elem' _ [] = False
66+
elem' x (y:ys) | x == y = True
67+
| otherwise = elem' x ys
68+
69+
-- 7. Define a recursive function merge :: Ord a => [a] -> [a] -> [a] that merges two
70+
-- sorted lists to give a single sorted list.
71+
merge :: Ord a => [a] -> [a] -> [a]
72+
merge [] ys = ys
73+
merge xs [] = xs
74+
merge (x:xs) (y:ys) | x <= y = x : merge xs (y:ys)
75+
| otherwise = y : merge (x:xs) ys
76+
77+
-- 8. Using merge, define a function msort :: Ord a => [a] -> [a] that sorts a list by
78+
-- merging its halves. Use halve :: [a] -> ([a],[a]) for this.
79+
halve :: [a] -> ([a], [a])
80+
halve xs = splitAt (length xs `div` 2) xs
81+
82+
msort :: Ord a => [a] -> [a]
83+
msort [] = []
84+
msort [x] = [x]
85+
msort xs = merge (msort h1) (msort h2)
86+
where
87+
(h1,h2) = halve xs
88+
89+
-- 9. Using the five-step process, construct functions that:
90+
-- a. calculate the sum of a list of numbers
91+
sum' :: [Int] -> Int
92+
sum' [] = 0
93+
sum' (n:ns) = n + sum' ns
94+
95+
-- b. take a given number of elements from the start of a list
96+
take' :: Int -> [a] -> [a]
97+
take' _ [] = []
98+
take' 0 xs = xs
99+
take' n (x:xs) = take' (n-1) xs
100+
101+
-- c. select the last element of a non-empty list
102+
last' :: [a] -> a
103+
last' [x] = x
104+
last' (_:xs) = last' xs

‎src/Ch7.hs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
module Ch7 where
2+
3+
import Data.Char
4+
5+
-- 1. Show how the list comprehension [f x | x <- xs, p x] can be re-expressed using map
6+
-- and filter.
7+
mNf :: (a -> b) -> (a -> Bool) -> [a] -> [b]
8+
mNf f p = map f . filter p
9+
10+
-- 2. Define the following higher-order functions on list:
11+
all' :: (a -> Bool) -> [a] -> Bool
12+
all' p = and . map p
13+
14+
any' :: (a -> Bool) -> [a] -> Bool
15+
any' p = or . map p
16+
17+
takeWhile' :: (a -> Bool) -> [a] -> [a]
18+
takeWhile' _ [] = []
19+
takeWhile' p (x:xs) | p x = x : takeWhile' p xs
20+
| otherwise = []
21+
22+
dropWhile' :: (a -> Bool) -> [a] -> [a]
23+
dropWhile' _ [] = []
24+
dropWhile' p (x:xs) | p x = dropWhile' p xs
25+
| otherwise = x:xs
26+
27+
-- 3. Redefine map f and filter p using foldr.
28+
map' :: (a -> b) -> [a] -> [b]
29+
map' f = foldr (\x xs -> f x:xs) []
30+
31+
filter' :: (a -> Bool) -> [a] -> [a]
32+
filter' p = foldr (\x xs -> if p x then x:xs else xs) []
33+
34+
-- 4. Using foldl, define a function dec2int :: [Int] -> Int that converts a decimal
35+
-- into an integer.
36+
dec2int :: [Int] -> Int
37+
dec2int = foldl (\x y -> x*10 + y) 0
38+
39+
-- 5. Define the higher-order functions curry and uncurry without looking at the library
40+
-- definitions.
41+
curry' :: ((a, b) -> c) -> a -> b -> c
42+
curry' f x y = f (x,y)
43+
44+
uncurry' :: (a -> b -> c) -> (a, b) -> c
45+
uncurry' f (x,y) = f x y
46+
47+
-- 6. Redefine the functions chop8, map f and iterate f using unfold.
48+
unfold :: (a -> Bool) -> (a -> b) -> (a -> a) -> a -> [b]
49+
unfold p h t x | p x = []
50+
| otherwise = h x : unfold p h t (t x)
51+
52+
type Bit = Int
53+
54+
chop8 :: [Bit] -> [[Bit]]
55+
chop8 = unfold null (take 8) (drop 8)
56+
57+
map2' :: (a -> b) -> [a] -> [b]
58+
map2' f = unfold null (f . head) tail
59+
60+
iterate2' :: (a -> a) -> a -> [a]
61+
iterate2' = unfold (const False) id
62+
63+
-- 7. Modify the binary string transmitter example to detect simple transmission errors
64+
-- using the concept of parity bits.
65+
bin2int :: [Bit] -> Int
66+
bin2int bits = sum [w*b | (w,b) <- zip weights bits]
67+
where weights = iterate (*2) 1
68+
69+
int2bin :: Int -> [Bit]
70+
int2bin 0 = []
71+
int2bin n = n `mod` 2 : int2bin (n `div` 2)
72+
73+
make8 :: [Bit] -> [Bit]
74+
make8 bits = take 8 (bits ++ repeat 0)
75+
76+
encode :: String -> [Bit]
77+
encode = concatMap (make8 . int2bin . ord)
78+
79+
decode :: [Bit] -> String
80+
decode = map (chr . bin2int) . chop8
81+
82+
transmit :: String -> String
83+
transmit = decode . channel . encode
84+
85+
channel :: [Bit] -> [Bit]
86+
channel = concatMap (checkParity . setParity) . chop8
87+
88+
oddOnes :: [Bit] -> Bool
89+
oddOnes = odd . length . filter (==1)
90+
91+
setParity :: [Bit] -> [Bit]
92+
setParity bits | oddOnes bits = bits ++ [1]
93+
| otherwise = bits ++ [0]
94+
95+
checkParity :: [Bit] -> [Bit]
96+
checkParity bits | parity = init bits
97+
| otherwise = error "Transmission error: 0-parity detected"
98+
where parity = last bits == 1
99+
100+
-- 8. Test your new string transmitter using a faulty communication channel that forgets
101+
-- the first bit, which can be modified using the tail function.
102+
faultyChannel :: p -> [Bit] -> [Bit]
103+
faultyChannel bits = channel . tail
104+
105+
-- 9. Define a function altMap :: (a -> b) -> (a -> b) -> [a] -> [b] that alternately
106+
-- applies uts two argument functions to successive elements in a list.
107+
altMap :: (a -> b) -> (a -> b) -> [a] -> [b]
108+
altMap f1 f2 = zipWith ($) fs
109+
where fs = cycle [f1,f2]
110+
111+
-- 0. Using altMap, define a function luhn :: [Int] -> Bool that implements the luhn
112+
-- algorithm from the chapter 4 for bank card numbers of any length.
113+
luhnDouble :: Int -> Int
114+
luhnDouble n | double > 9 = double - 9
115+
| otherwise = double
116+
where
117+
double = n*2
118+
119+
luhn :: [Int] -> Bool
120+
luhn = (==0)
121+
. (`mod` 10)
122+
. sum
123+
. altMap luhnDouble id

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /