Real World Haskell 4章 練習問題4-4

concat実装

myconcat :: [[a]] -> [a]
myconcat = foldr (++) []

ProductName Real World Haskell―実戦で学ぶ関数型言語プログラミング
Bryan O'Sullivan,John Goerzen,Don Stewart
オライリージャパン / ¥ 3,990 ()
在庫あり。

Real World Haskell 4章 練習問題

4章の練習問題

ProductName Real World Haskell―実戦で学ぶ関数型言語プログラミング
Bryan O'Sullivan,John Goerzen,Don Stewart
オライリージャパン / ¥ 3,990 ()
在庫あり。

1

import Data.Char (digitToInt)

asInt_fold :: String -> Int
asInt_fold cs@(c:cs') | c == '-'  = negate $ foldl step 0 $ map digitToInt cs'
                      | otherwise = foldl step 0 $ map digitToInt cs
                      where step x y = 10*x + y


-- *Main> asInt_fold "101"
-- 101
-- *Main> asInt_fold "-31337"
-- -31337
-- *Main> asInt_fold "1798"
-- 1798

2

-- 2
import Data.Char (digitToInt)

asInt_fold :: String -> Int
asInt_fold [] = 0
asInt_fold "-" = 0
asInt_fold cs@(c:cs') | c == '-'  = negate $ foldl step 0 $ map digitToInt cs'
                      | otherwise = foldl step 0 $ map digitToInt cs
                      where step x y = 10*x + y

-- *Main> asInt_fold ""
-- 0
-- *Main> asInt_fold "-"
-- 0
-- *Main> asInt_fold "-3"
-- -3
-- *Main> asInt_fold "2.7"
-- *** Exception: Char.digitToInt: not a digit '.'
-- *Main> asInt_fold "314159265358979323846"
-- 1537529798

3

なんか汚い。

import Data.Char (digitToInt,isDigit)
type ErrorMessage = String

asInt_fold :: String -> Either ErrorMessage Int
asInt_fold [] = Right 0
asInt_fold "-" = Right 0
asInt_fold cs@(c:cs') | c == '-'  = case foldl step (Right 0) cs' of
                                      Right x  -> Right  (negate x)
                                      Left x   -> Left x 
                      | otherwise = foldl step (Right 0) cs
                      where step (Left x) _ = Left x
                            step (Right x) y = case isDigit y of
                                                 True  -> Right (10*x + (digitToInt y))
                                                 False -> Left ("non-digit '" ++ [y] ++ "'")

Real World Haskell 4章 (foldrを使ってfoldlを定義する)

RWHの4章にfoldlをfoldrによって書く例が載っていたのだけど、ぱっと見ただけではわからなかったので良く考えてみた。

ProductName Real World Haskell―実戦で学ぶ関数型言語プログラミング
Bryan O'Sullivan,John Goerzen,Don Stewart
オライリージャパン / ¥ 3,990 ()
在庫あり。

myFoldl :: (a -> b -> a) -> a -> [b] -> a

myFoldl f z xs = foldr step id xs z
    where step x g a = g (f a x)

これは結局

foldr step id xs

によって出来た関数に本来の初期値であるzを与えていると。

例えば

myFoldl (+) 0 [1..3]

だと

foldr (+) id [1..3]

により

\x -> (+3) $ (+2) $ (+1) (id x)

が出来てこれに元の初期値0が与えられて(3+(2+(1+0)))となる。

参考

おりがみプログラミング

リストを定義してmap append concatを実装

ProductName 関数プログラミングの楽しみ

オーム社 / ¥ 4,410 ()
在庫あり。

data List a = Nil | Cons a (List a) deriving Show

wrap :: a -> List a
wrap x = Cons x Nil

nil :: List a -> Bool
nil Nil = True
nil (Cons x xs) = False

foldL :: (a -> b -> b) -> b -> List a -> b
foldL f e Nil = e
foldL f e (Cons x xs) = f x (foldL f e xs)

mapL :: (a  -> b) -> List a -> List b
mapL f Nil = Nil
mapL f (Cons x xs) = Cons (f x) (mapL f xs)

appendL :: List a -> List a -> List a
appendL Nil ys = ys
appendL (Cons x xs) ys = Cons x (appendL xs ys)

concatL :: List (List a) -> List a
concatL Nil = Nil
concatL (Cons (Cons x xs) xss) = appendL (Cons x xs) (concatL xss)

追記 091025

foldLを使って書きなおすという問題だったので

mapL :: (a  -> b) -> List a -> List b
mapL f = foldL (Cons . f) Nil

appendL :: List a -> List a -> List a
appendL xs ys = foldL Cons ys xs

concatL :: List (List a) -> List a
concatL xs = foldL appendL Nil

Real World Haskell 3章 (グラハムスキャン)

練習問題3-9,10,11,12

ProductName Real World Haskell―実戦で学ぶ関数型言語プログラミング
Bryan O'Sullivan,John Goerzen,Don Stewart
オライリージャパン / ¥ 3,990 ()
在庫あり。

3-12はわからなかったので、酔いどれコードを参考にした。というかほとんど写経。

量子男のささいなログにも書いてあったけど3-11の使いどころがいまいちわからない。この場合もリスト全部じゃなくて最後のほうだけチェックすればいいような気がした。

-- 3-9,3-10,3-11

data Direction = CounterClockwise | Clockwise | Straight deriving (Show,Eq)
type Pos = (Float,Float)

calcpos :: Pos -> Pos -> Pos -> Direction
calcpos a b c | iprod >  0 = CounterClockwise
              | iprod <  0 = Clockwise
              | iprod == 0 = Straight
              where iprod = ((fst a) - (fst b)) * ((snd c) - (snd b))
                          - ((snd a) - (snd b)) * ((fst c) - (fst b))

directions :: [Pos] -> [Direction]
directions []         = []
directions (x:[])     = []
directions (x:y:[])   = []
directions (x:y:z:zs) = calcpos x y z : directions (y:z:zs)

-- 3-12
sortCoordinate :: [Pos] -> [Pos]
sortCoordinate ps = sortBy cmp ps
    where cmp a b | snd a < snd b = LT 
                  | snd a > snd b = GT
                  | fst a < fst b = LT
                  | fst a > fst b = GT
                  | otherwise = EQ

sortAngle :: Pos -> [Pos] -> [Pos]
sortAngle p ps = sortBy cmp ps
    where cmp a b = compare (cot b) (cot a)
              where cot c = (fst c - fst p) / (snd c - snd p)

gsort :: [Pos] -> [Pos]
gsort ps = let csort = sortCoordinate ps 
               lower = head csort
           in  lower : sortAngle lower (tail csort)

isCounterClockwise :: [Direction] -> Bool
isCounterClockwise [] = False
isCounterClockwise (x:xs) | x == CounterClockwise = True
                          | otherwise = isCounterClockwise xs

scan :: [Pos] -> [Pos] -> [Pos]
scan [] (y1:y2:ys) = scan [y1,y2] ys
scan xs []         = xs
scan xs (y:ys) | isCounterClockwise (directions (xs++[y])) = scan (init xs) (y:ys)
               | otherwise                    = scan (xs++[y]) ys

graham :: [Pos] -> [Pos]
graham xs = scan [] $ gsort xs

-- データ生成用
randX :: [Float]
randX = randomRs (-100,100) (mkStdGen 5)

randY :: [Float]
randY = randomRs (-100,100) (mkStdGen 3)

randPoss :: Int -> [(Float,Float)]
randPoss n = take n $ zip randX randY

Real World Haskell 3章

二周目。今度は問題を解きながら。

というわけで練習問題

回文をつくるのと回文かどうかをチェックする。後者は回文を作ってみて元の文を二つ並べたものと一致するかをチェック

-- 3-4    
mypalin :: [a] -> [a]
mypalin [] = []
mypalin (x:xs) = [x] ++ mypalin xs ++ [x]

-- 3-5
ismypalin :: Eq a => [a] -> Bool
ismypalin xs = (mypalin xs) == (xs ++ xs)

ProductName Real World Haskell―実戦で学ぶ関数型言語プログラミング
Bryan O'Sullivan,John Goerzen,Don Stewart
オライリージャパン / ¥ 3,990 ()
在庫あり。

第九回Haskell読書会@富士コミュティF

9月の読書会は富士市の吉原でやります。

ProductName プログラミングHaskell
Graham Hutton
オーム社 / ¥ 2,940 ()
在庫あり。

  • 日 時 : 2010年9月25日(土) 13:00~17:00
  • 場 所 :富士市民活動センター・コミュニティF ( http://com-f.net/index.html )
  • 地 図 : http://com-f.net/access.html

10章(型)のとこ。

プログラミングHaskell 13章

13章の問題は証明ばっかりなので、紙に書いてけばOKな感じ。

ProductName プログラミングHaskell
Graham Hutton
オーム社 / ¥ 2,940 ()
在庫あり。

というわけで、二周しつつ問題を解き終えた。

これは名著だよなぁと改めて思ったのであった。

プログラミングHaskell 12章

12章最後の問題

data Tree a = Leaf | Node (Tree a) a (Tree a) deriving Show

という型に対してrepeat,takeを実装する

data Tree a = Leaf | Node (Tree a) a (Tree a) deriving Show

repeatTree :: a -> Tree a
repeatTree x = Node (repeatTree x) x (repeatTree x)

takeTree :: Int -> Tree a -> Tree a
takeTree 0 _ = Leaf
takeTree (n+1) Leaf = Leaf
takeTree (n+1) (Node a b c) = Node (takeTree n a) b (takeTree n c)

replicateTree :: Int -> a -> Tree a
replicateTree n = takeTree n . repeatTree

型に対して適切に実装すればリストに対して操作するように自然に扱える。

ProductName プログラミングHaskell
Graham Hutton
オーム社 / ¥ 2,940 ()
在庫あり。

プログラミングHaskell 10章,11章の問題解いた

10章は改めて読みなおしてみて、面白いなぁと。

ProductName プログラミングHaskell
Graham Hutton
オーム社 / ¥ 2,940 ()
在庫あり。

写経して問題解くとやっぱその分理解が深まるなぁ。

この調子で残り二章の問題解いたら、RWHの二周目でもしようかな。

ProductName Real World Haskell―実戦で学ぶ関数型言語プログラミング
Bryan O'Sullivan,John Goerzen,Don Stewart
オライリージャパン / ¥ 3,990 ()
在庫あり。