Real World Haskell 19章

エラー処理

Eitherを利用すると失敗の場合にも成功の場合にもデータ(Right)が付随する。

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

tryとhandleも使える。

try :: IO a -> IO (Either Exception a)
handle :: (Exception e) => (e -> IO a) -> IO a -> IO a

19.3.1

import Control.Monad.Error
import Control.Monad.State
import qualified Data.ByteString.Char8 as B

data ParseError = NumericOverflow
                | EndOfInput
                | Chatty String
                  deriving (Eq, Ord, Show)

instance Error ParseError where
    noMsg  = Chatty "oh noes!"
    strMsg = Chatty

newtype Parser a = P {
      runP :: ErrorT ParseError (State B.ByteString) a
    } deriving (Monad, MonadError ParseError)

liftP :: State B.ByteString a -> Parser a
liftP m = P (lift m)

satisfy :: (Char -> Bool) -> Parser Char
satisfy p = do
  s <- liftP get
  case B.uncons s of
    Nothing ->  throwError EndOfInput
    Just (c, s')
         | p c ->  liftP (put s') >> return c
         | otherwise -> throwError (Chatty "satisfy failed")

optional :: Parser a -> Parser (Maybe a)
optional p = (Just `liftM` p) `catchError` \_ -> return Nothing

runParser :: Parser a -> B.ByteString -> Either ParseError (a, B.ByteString)
runParser p bs = case runState (runErrorT (runP p)) bs of
                   (Left err, _) -> Left err
                   (Right r, bs) -> Right (r, bs)

Real World Haskell 18章

モナド変換子

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

  • モナドの上に積み上げる
  • IOは常に底

この章はあとでもう一度読みなおす。

Real World Haskell 15章

モナドを使ったプログラミング

ProductName Real World Haskell―実戦で学ぶ関数型言語プログラミング
Bryan O'Sullivan
オライリージャパン / 3990円 ( 2009-10-26 )


持ち上げの一般化(15.2)

liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
Prelude Control.Monad> :t liftM

liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r
Prelude Control.Monad> :t ap
ap :: (Monad m) => m (a -> b) -> m a -> m b

liftM(N)はliftMとapを使って一般化できる。

Readerモナドを大体理解した(15.6)。

newtype Reader e a = R { runReader :: e -> a }

instance Monad (Reader e) where
    return a = R $ \_ -> a
    m >>= k  = R $ \r -> runReader (k (runReader m r)) r

ask :: Reader e e
ask = R id

askで得た環境を引き回す。

*Main Data.Char> runReader (ask >>= \x -> return (x*3)) 2
6

askで常に同じ環境が返ってくる、読み取り専用のStateみたいなもんか。

Real World Haskell 後半

15章を境にpost-itが激減してる。

1286536364

PRMLの上下みたいなパターンだ

二周目はここからが本番。

Real World Haskell 14章

二周目読んでて今のとこ一番感動した。

14.13のモナドとファンクタのところで

join :: m (m a) -> m a

として

(>>=) :: AltMonad m => m a -> (a -> m b) -> m b
xs >>= f = join (fmap xs)

となるが、ここへ至る過程が素晴らしい。

14.10のリストモナドにおけるバインド(>>=)を型から構成していく過程を経て拡張していくのでここをよく読んでおくとよい。

ちなみにリストモナドのバインドは

xs (>>=) f = concat (map f xs)

それぞれ、

Prelude> :t map
map :: (a -> b) -> [a] -> [b]
Prelude> :t concat
concat :: [[a]] -> [a]

リストの型が[] a つまり[a]であることから類推できる。

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

Real World Haskell 9,10章

持ち上げとファンクタ。この章は面白い。

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

  • maybeとhandleの使い方
  • 将来の変更に備える最良の方法は実装をユーザーに見せないこと
  • functorのインスタンスにできるのは型パラメータがひとつだけあるような型
  • ファンクタは形を保存しなければならない

Real World Haskell 8章

maximumは空リストを取れない

*Main> maximum [1..5]
5
*Main> maximum []
*** Exception: Prelude.maximum: empty list

そこで、ちょっと工夫する

safemaximum :: Ord a => [Maybe a]  -> Maybe a
safemaximum = maximum . (Nothing:)

使ってみる

*Main> safemaximum $ map Just [1..5]
Just 5
*Main> safemaximum []
Nothing

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

Real World Haskell 7章

入出力

環境変数をmapM_を使って出力してみた。

import System.Environment
main = do env <- getEnvironment 
          mapM_ (putStrLn . show) env

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

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

takeWhileの実装

まずは再帰で

mytakeWhile :: (a  -> Bool) -> [a] -> [a]
mytakeWhile f [] = []
mytakeWhile f (x:xs) = case f x of
                       True   -> x : mytakeWhile f xs
                       False  -> [] 

続いてfoldrを使って

mytakeWhile' :: (a  -> Bool) -> [a] -> [a]
mytakeWhile' f xs = foldr step [] xs
    where step x ys | f x    = x : ys
                    | otherwise = []


-- *Main> mytakeWhile' (<3) [1,2,3,4,5,4,3,2,1]
-- [1,2]

最初書いてたときにコレって

1:2:3:[]:[]:3:2:1:[]

ってなるよなとか思ったんだけどfoldrの定義見て

-- foldr            :: (a -> b -> b) -> b -> [a] -> b
-- -- foldr _ z []     =  z
-- -- foldr f z (x:xs) =  f x (foldr f z xs)

再帰になってるから[]が返った時点で終了すんのねと。

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