7. CASE3:IO(ここから11章)
main = do line <- getLine
let line’ = reverse line
putStrLn $ “You said “ ++ line’ ++ “ backwards!”
putStrLn $ “Yes, you said “ ++ line’ ++ “ backwards!”
↓
main = do line <- fmap reverse getLine
putStrLn $ “You said “ ++ line ++ “ backwards!”
putStrLn $ “Yes, you said “ ++ line ++ “ backwards!”
↓
…ちょっと、嬉しい
8. CASE3:IO(ここから11章)
p195 todo.hs source
view :: [String] -> IO ()
view [fileName] = do
contents <- readFile fileName
let todoTasks = lines contents
numberedTasks = zipWith
(n line -> show n ++ " - " ++ line)
[0..] todoTasks
putStr $ unlines numberedTasks
↓
view :: [String] -> IO ()
view [fileName] = do
numberedTasks <- fmap (zipWith
(n line -> show n ++ " - " ++ line)
[0..] . lines ) $readFile fileName
putStr $ unlines numberedTasks
↓
なかなか嬉しい!
11. 「文脈」のお話
Functor クラス実装
class Functor f where
fmap :: (a -> b) -> f a -> f b
のfを文脈(Computational context)と呼ぶ
例:
(->) r 型入力を一つすると函数型を返す文脈
[] 型入力を一つするとリスト型を返す文脈
12. 「持ち上げ」のお話
(ー>)を2つの型をとって函数を返す型コンストラクタ
と見立てる
class Functor f where
fmap :: (a -> b) -> f a -> f b
↓ クラス実装の視点を変えて
fmap :: (a -> b) -> (f a -> f b)
と見て、fmapを「元の函数と似てるけどFunctor値をとっ
てFunctor値を返す函数」を返すメソッドと見立てること
もできる。この操作を持ち上げ(lifting)と呼ぶ。
13. 「持ち上げ」のお話
例:
ghci> let shout = fmap (++ “!”)
ghci> :t shout
shout :: Functor f => f [Char] -> f [Char]
ghci> shout [“ha”,“ka”,“ta”,”no”]
[“ha!”,“ka!”,”ta!”,”no!”]
「持ち上げられた函数」
※これまでの
fmapが函数とFunctor値を引数とする二引数函数である
見方が否定されたわけではない。
15. ファンクター則
例:(->) r
instance Functor ((->) r) where
fmap f g = f . g
第一則: fmap id g = id . g = id (g)
第二則: fmap (f . g) h = f . g . h
= f (g . h)
= fmap f (g . h)
= fmap f (fmap g h)
16. ファンクター則を満たさないファンクター
data CMaybe a = CNothing
| CJust Int a deriving (Show)
instance Functor CMaybe where
fmap f CNothing = CNothing
fmap f (CJust count x)
= CJust (count+1) (f x)
fmap id (CJust 0 “haha”)
≠ id (CJust 0 “haha”) より
第一則: fmap id (f a) = id (f a)
を満たさず、Functorとして不適切
18. アプリカティブファンクター
このFunctor内部の函数を使ってFunctor値を写したい!
しかし、普通に適用しようとすると…
例:
ghci> let a = fmap (++) (Just “hey”)
ghci> fmap a (Just “ you!”)
<interactive>:31:6:
Couldn't match expected type `a0 -> b0'
with actual type `Maybe ([Char] -> [Char])'
In the first argument of `fmap', namely `a'
In the expression: fmap a (Just " you!")
In an equation for `it': it = fmap a (Just " you!")
_人人人人人人人_
となり、うまくいかない >アプリカティブ <
そこで! > ファンクター <
 ̄^Y^Y^Y^Y^Y^Y^Y
20. アプリカティブファンクター
例1:Maybe Applicative Functor
instance Applicative Maybe where
pure = Just
Nothing <*> _ = Nothing
(Just f) <*> sth = fmap f sth
ghci> let a = fmap (++) (Just “hey”)
ghci> a <*> (Just “ you!”)
Just "hey you!"
※普通のファンクターの場合ファンクター内の関数適用の結果をファンクター外に
取り出す一般的な方法は無い。
21. アプリカティブファンクター
便利な記号<$>
pure (+) <*> Just 3 <*> Just 5
をもっと簡潔にしたい!
アプリカティブ則(ファンクタ則のようなもの)の一つに
pure f <*> x = fmap f x があり
更に短くf <$> xと書ける(Control.Applicative内)
(<$>) :: (Functor f) => (a->b) -> f a -> f b
f <$> x = fmap f x
(ちなみにghci> :t ($) ▶ ($) :: (a -> b) -> a -> b )
22. アプリカティブファンクター
例2:List Applicative Functor
instance Applicative [] where
pure x = [x]
fs <*> xs = [f x| f <- fs, x <- xs]
ghci> pure “Hey” :: [String]
[“Hey”] (::=型注釈,p30参照)
・定義から可能な組み合わせ全てをリストとして提示する
ghci> filter (>50) $ (*) <$> [2,5,10] <*> [8,10,11]
[55,80,100,110] (::=型注釈,p30参照)
24. アプリカティブファンクター
例4:((->) r) Applicative Functor
instance Applicative ((->) r) where
pure x = (_ -> x)
f <*> g = x -> f x (g x)
pure :: a -> (r -> a)
(<*>) :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
ghci> (+) <$> (+3) <*> (*100) $ 5
508
(ここで:t (+) <$> (+3) ▶ (+) <$> (+3) :: Num a => a -> a -> a)
ghci> (x y z -> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5
[8.0,10.0,2.5]
・<*>,<$>は頭の函数に引数函数を渡す為の道具と割切る
25. アプリカティブファンクター
例5:ZipList Applicative Functor
instance Applicative ZipList where
pure x = ZipList (repeat x)
ZipList fs <*> ZipList xs
= ZipList (zipWith (f x -> f x) fs xs)
・[]の<*>は可能な組み合わせすべてを結果に出す
・ZipListの<*>はリストの個々の函数を対応する位置の
値に適用して結果に出す
・ZipListをアプリカティブ・スタイルで使えばzipWith
函数群を使う必要がない
26. アプリカティブ則
アプリカティブファンクターにもファンクター則同様に
写像性 pure f <*> x = fmap f x
恒等函数保存 pure id <*> v = v
分配則 pure (.) <*> u <*> v <*> w
= u <*> (v <*> w)
準同型 pure f <*> pure x = pure (f x)
交換則 u <*> pure y = pure ($ y) <*> u
が成立
27. アプリカティブの便利な函数達
Control.Applicative内には<$>の他にも
liftA2::(Applicative f) => (a->b->c)
-> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b
やその他様々有用な函数(<$,<**>,liftA3..)が存在
また、ユーザ定義により(<*),(*>),等の函数も使えるよ
うになるらしい。詳しくは以下URLを参照
http://www.haskell.org/ghc/docs/6.12.1/html/libraries/base/
Control-Applicative.html