第2回スタートHaskellの範囲を予習しました。

第2回スタートHaskellの範囲の演習問題を解いてみました。
間違っている箇所が多々あると思いますが、ここに載せておきます。

第2回スタートHaskellの範囲はプログラミングHaskellの以下の章です。

5章 練習問題の解答

import Data.Char

-- 5.7.1
sumOfSqure = sum [x * x | x <- [1..100]]

-- 5.7.2
myreplicate :: Int -> a -> [a]
myreplicate n obj = [obj | x <- [1 .. n]]

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

-- 5.7.4
perfects :: Int -> [Int]
perfects n = [x | x <- [1..n], x == sum (divisors x)]
             where
               divisors = (\ n -> [x | x <- [1..n], n `mod` x == 0 && (not (n == x))])

-- 5.7.5
twogen = concat [[(x, y)|y <- [4,5,6]] | x <- [1,2,3]]

-- 5.7.6
find :: Eq a => a -> [(a,b)] -> [b]
find k t = [v | (k',v) <- t,k == k']

positions :: Eq a => a -> [a] -> [Int]
positions x xs = find x [(xs!!n, n) | n <- [0 .. endIndex]]
                 where
                   endIndex = length xs -1

-- 5.7.7
scalarproduct :: [Int] -> [Int] -> Int
scalarproduct xs ys = sum [xs!!n * ys!!n | n <- [0 .. (length xs -1)]]

-- 5.7.8
let2int :: Char -> Int
-- let2int c  = ord c - ord 'a'
let2int c | isUpper c = ord c - ord 'A' + 260
          | otherwise = ord c - ord 'a'


int2let :: Int -> Char
int2let n | n < 260 = chr (ord 'a' + n)
          | otherwise = chr(ord 'A' + n - 260) 

shift :: Int -> Char -> Char
shift n c | isLower c = int2let ((let2int c + n) `mod` 26)
          | isUpper c = int2let (((let2int c + n) `mod` 26) + 260)
          | otherwise = c

encode :: Int -> String -> String
encode n xs = [shift n x | x <- xs]

table :: [Float]
table = [8.2, 1.5, 2.8, 4.3, 12.7, 2.2, 2.0, 6.1, 7.0, 0.2, 0.8, 4.0, 2.4,
	 6.7, 7.5, 1.9, 0.1, 6.0, 6.3, 9.1, 2.8, 1.0, 2.4, 0.2, 2.0, 0.1]

percent :: Int -> Int -> Float
percent n m = (fromIntegral n / fromIntegral m) * 100

lowers :: String -> Int
lowers xs = length [x|x <- xs, isLower x]

count :: Char -> String -> Int
count x xs = length [x' | x' <- xs, x == x']

freqs :: String -> [Float]
freqs xs = [percent (count x xs) n | x <- ['a' .. 'z']]
	   where
             n = lowers xs

chisqr :: [Float] -> [Float] -> Float
chisqr os es = sum [((o -e) ** 2) / e | (o,e) <- zip os es]

rotate :: Int -> [a] -> [a]
rotate n xs = drop n xs ++ take n xs

crack :: String -> String
crack xs = encode (-factor) xs
           where
             factor = head (positions (minimum chitab) chitab)
	     chitab = [chisqr (rotate n table') table | n <- [0..25]]             
             table' = freqs xs


6章 練習問題の解答

-- ex6.8.1

(***) :: Int -> Int -> Int
(***) 0 _ = 0
(***) _ 0 = 1
(***) x n | n > 0 = x * (x *** (n - 1))
          | otherwise = error "n: invalid arg"

-- ex6.8.2
length' :: [a] -> Int
length' [] = 0
length' (_:xs) = 1 + length' xs

drop' :: Int -> [a] -> [a]
drop' 0 [] = []
drop' 0 (x:xs) = x:xs
drop' n [] = []
drop' n (x:xs) = drop' (n - 1) xs

init' :: [a] -> [a]
init' [_] = []
init' (x:xs) = x : init' xs

-- ex6.8.3
and' :: [Bool] -> Bool
and' [] = True
and' (x:xs) | x = and' xs
            | otherwise = False

concat' :: [[a]] -> [a]
concat' [] = []
concat' (x:xs) = x ++ (concat' xs)

replicate' :: Int -> a -> [a]
replicate' 0 _ = []
replicate' n x = x : (replicate' (n - 1) x)

(!!!) :: [a] -> Int -> a
(!!!) [] _ = error "index too large"
(!!!) (x:xs) 0 = x
(!!!) (x:xs) n = xs !!! (n -1)

elem' :: Eq a => a -> [a] -> Bool
elem' _ [] = False
elem' x xs | x == (head xs) = True
           | otherwise = elem' x (tail xs)

-- ex6.8.4
merge' :: Ord a => [a] -> [a] -> [a]
merge' [] xs = xs
merge' xs [] = xs
merge' (x:xs) (y:ys) | x < y = x:(merge' xs (y:ys))
                     | otherwise = y:(merge' (x:xs) ys)

-- ex6.8.5
msort :: Ord a => [a] -> [a]
msort [] = []
msort [x] = [x]
msort [x,y] = merge' [x] [y]
msort xs = merge' (msort forth) (msort back)
           where
              i = (length xs) `div` 2
              forth = take i xs
              back = drop i xs

-- ex6.8.6
sum' :: Num a => [a] -> a
sum' [] = 0
sum' (x:xs) = x + (sum' xs)

take' :: Int -> [a] -> [a]
take' 0 _ = []
take' n [] = []
take' n (x:xs) = x:(take' (n - 1) xs)

last' :: [a] -> a
last' [] = error "empty list"
last' [x] = x
last' (x:xs) = last' xs


7章 練習問題の解答

import Data.Char

-- ex7.8.1
listComprehension :: (a -> b) -> (a -> Bool) -> [a] -> [b]
listComprehension f p xs = map f (filter p xs)

-- ex7.8.2
all' :: (a -> Bool) -> [a] -> Bool
all' p xs = and (map p xs)

any' :: (a -> Bool) -> [a] -> Bool
any' p xs = or (map p xs)

takeWhile' :: (a -> Bool) -> [a] -> [a]
takeWhile' p [] = []
takeWhile' p (x:xs) | p x = x:(takeWhile' p xs)
                    | otherwise = []

dropWhile' :: (a -> Bool) -> [a] -> [a]
dropWhile' p [] = []
dropWhile' p (x:xs) | p x = dropWhile' p xs
                    | otherwise = x:xs

-- ex7.8.3
map' :: (a -> b) -> [a] ->  [b]
map' f = foldr (\ x y -> (f x):y) [] 

filter' :: (a->Bool)->[a] -> [a]
filter' p = foldr (\ x y -> if p x then x:y else y) []

-- ex7.8.4
dec2int :: [Int] -> Int
dec2int xs = foldr f 0 l
             where
               f = (\ (x,p) y -> x * (10 ^ p) + y)
               l = zip (reverse xs) [0 .. (length xs)]

-- ex7.8.5
compose :: [a -> a] -> (a -> a)
compose = foldr (.) id
-- sumsqreven = compose [sum , map ((^) 2) , filter even]
-- sumの型が sum :: Num a => [a] -> a で、リストを返さない。
-- このためsumだけリストに入れる事が出来ない。
-- 以下のように合成することは出来る。
sumsqreven = sum . map ((^) 2) . (filter even)

-- ex7.8.6
add :: (Int,Int) -> Int
add (x,y) = x + y

curry' :: ((a, b) -> c) -> a -> b -> c
curry' f x y = f (x,y)

add' x y = x + y
uncurry' :: (a -> b -> c) -> ((a, b) -> c)
uncurry' f = (\ (x,y) -> f x y)

-- ex7.8.7
unfold p h t x | p x = []
               | otherwise = h x : unfold p h t (t x)

int2bin = unfold (== 0) (`mod` 2) (`div` 2)

type Bit = Int
chop8 :: [Bit] -> [[Bit]]
chop8 bits = unfold null (take 8) (drop 8) bits

map'' :: (a -> b) -> ([a] -> [b])
map'' f = unfold null (f . head) (tail) 

iterate' :: (a -> a) -> a -> [a]
iterate' f = unfold (\x -> False) id f


-- ex7.8.8
make8 :: [Bit] -> [Bit]
make8 bits = take 8 (bits ++ repeat 0)

bin2int :: [Bit] -> Int
bin2int bits = sum [ w * b | (w, b) <- zip weights bits]
               where
                 weights = iterate (* 2) 1

encode :: String -> [Bit]
encode = concat . map (make8 . int2bin . ord)

addParityBit :: [Bit] -> [Bit]
addParityBit bits = concat (map (\x -> (parityBit x):x) (chop8 bits))
                    where
                       parityBit = (\x -> (sum x) `mod` 2)

encode' :: String -> [Bit]
encode' str = addParityBit (encode str)

decode :: [Bit] -> String
decode = map (chr . bin2int) . chop8

chop9 :: [Bit] -> [[Bit]]
chop9 bits = unfold null (take 9) (drop 9) bits

correctParityBit :: [[Bit]] -> Bool
correctParityBit bits = and (map (\x-> ((sum (tail x)) `mod` 2) == head x) bits)

removeParityBit :: [Bit] -> [Bit]
removeParityBit bits = concat (map tail (chop9 bits))

decode' :: [Bit] -> String
decode' bits | correctParityBit (chop9 bits) = decode (removeParityBit bits)
             | otherwise = error "decode fail"

-- ex7.8.9
transmit :: String -> String
transmit = decode' . id . encode'

transmitWithError :: String -> String
transmitWithError = decode' . tail .encode'