Upcoming SlideShare
×

# Applicative functor

3,266 views

Published on

Published in: Technology
3 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

Views
Total views
3,266
On SlideShare
0
From Embeds
0
Number of Embeds
256
Actions
Shares
0
18
0
Likes
3
Embeds 0
No embeds

No notes for slide
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• \n
• ### Applicative functor

1. 1. ファンクターからアプリカティブファンクターへ @UsrNameu1
3. 3. ファンクター復習（７章より）ファンクターとは？・全体を写せる（map over）性質をもつ型クラス型クラス実装class Functor f wherefmap :: (a -> b) -> f a -> f bf:型コンストラクタ（:k f で f:: *->* を返す)
4. 4. CASE1：LISTFunctor インスタンス宣言instance Functor [] where fmap = mapmap :: (a->b) -> [a] -> [b]↑(:k [] で []:*->*が返ってくる）ghci> fmap (*2) [1..3][2,4,6]
5. 5. CASE2：MAYBEFunctor インスタンス宣言instance Functor Maybe where fmap f (Just x) = Just (f x) fmap f Nothing = Nothing↑（:k MaybeでMaybe::*->*が返ってくる）ghci>fmap (*2) (Just 200)Just 400 ＿人人人人人人人人人人人＿  ＞箱の中身だけを変えて返す＜ ￣^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y￣
6. 6. CASE3：IO（ここから11章）Functor インスタンス宣言instance Functor IO where fmap f action = do result <- action return (f result)↑resultに束縛されたactionにfを適用して返す⇢何が嬉しいのか？
7. 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. 8. CASE3：IO（ここから11章）p195 todo.hs sourceview :: [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 ↓ なかなか嬉しい！
9. 9. CASE4：((->) r)そもそも(->)とは？⇢函数引数と返り値の型を（ー＞）で区切り、返り値の型を常に宣言の最後に置く（ｐ２５） ↓ 視点を変えて（ー＞）を２つの型をとって函数を返す型コンストラクタと見立てる （実際 :k (->) で(->) :: * -> * -> * を返す）
10. 10. CASE4：((->) r)ー＞のままではFunctorとして使えないため一つ引数の型rをとって((->) r)を新しいFunctorと見立てる（∵ :k ((->) Int) ▶ ((->) Int) :: * -> *） ↓Functor インスタンス宣言instance Functor ((->) r) where fmap f g = (x -> f (g x)) fmap = (.) fmap::(a->b)->((->)r a)->((->)r b)= fmap::(a->b)->(r->a)->(r->b)
11. 11. 「文脈」のお話Functor クラス実装class Functor f where fmap :: (a -> b) -> f a -> f bのfを文脈（Computational context）と呼ぶ例：(->) r  型入力を一つすると函数型を返す文脈[]    型入力を一つするとリスト型を返す文脈
12. 12. 「持ち上げ」のお話（ー＞）を２つの型をとって函数を返す型コンストラクタと見立てるclass Functor f where fmap :: (a -> b) -> f a -> f b  ↓ クラス実装の視点を変えて fmap :: (a -> b) -> (f a -> f b)と見て、fmapを「元の函数と似てるけどFunctor値をとってFunctor値を返す函数」を返すメソッドと見立てることもできる。この操作を持ち上げ（lifting）と呼ぶ。
13. 13. 「持ち上げ」のお話例：ghci> let shout = fmap (++ “!”)ghci> :t shoutshout :: Functor f => f [Char] -> f [Char]ghci> shout [“ha”,“ka”,“ta”,”no”][“ha!”,“ka!”,”ta!”,”no!”] 「持ち上げられた函数」※これまでの fmapが函数とFunctor値を引数とする二引数函数である 見方が否定されたわけではない。
14. 14. ファンクター則Functorクラスのインスタンスには２つのきまりがある第一法則（恒等函数の保存）fmap id (f a) = id (f a)第二法則（合成函数の分配）fmap (g . h) (f a) = fmap g (fmap h (f a))※法則は数学的要請（圏論）による、下記リンクを参照http://ja.wikibooks.org/wiki/Haskell/%E5%9C%8F%E8%AB%96
15. 15. ファンクター則例：(->) rinstance 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. 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として不適切
17. 17. アプリカティブファンクター二引数函数をfmapを用いてFunctor値に適用してみる例：ghci>:t fmap (++) (Just “hey”)  fmap (++) (Just “hey”) :: Maybe([Char] -> [Char])Functor内部に函数が入った！ ↑カリー化された複数引数函数に部分適用が施され、函数を値として返すため （ｐ６２参照）
18. 18. アプリカティブファンクターこのFunctor内部の函数を使ってFunctor値を写したい！ しかし、普通に適用しようとすると…例：ghci> let a = fmap (++) (Just “hey”)ghci> fmap a (Just “ you!”)<interactive>:31:6: Couldnt 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
19. 19. アプリカティブファンクターControl.Applicativeモジュール内class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f bpureは文脈内に型を置く函数(<*>)はfmapの函数引数が文脈内にあっても適用可能なグレードアップバージョン
20. 20. アプリカティブファンクター例１：Maybe Applicative Functorinstance Applicative Maybe where pure = Just Nothing <*> _ = Nothing (Just f) <*> sth = fmap f sthghci> let a = fmap (++) (Just “hey”)ghci> a <*> (Just “ you!”)Just "hey you!"※普通のファンクターの場合ファンクター内の関数適用の結果をファンクター外に 取り出す一般的な方法は無い。
21. 21. アプリカティブファンクター便利な記号<\$>pure (+) <*> Just 3 <*> Just 5をもっと簡潔にしたい！アプリカティブ則（ファンクタ則のようなもの）の一つにpure f <*> x = fmap f x があり更に短くf <\$> xと書ける（Control.Applicative内）(<\$>) :: (Functor f) => (a->b) -> f a -> f bf <\$> x = fmap f x （ちなみにghci> :t (\$) ▶ (\$) :: (a -> b) -> a -> b )
22. 22. アプリカティブファンクター例２：List Applicative Functorinstance Applicative [] where pure x = [x] fs <*> xs = [f x| f <- fs, x <- xs]ghci> pure “Hey” :: [String][“Hey”] （::=型注釈,ｐ３０参照）・定義から可能な組み合わせ全てをリストとして提示するghci> filter (>50) \$ (*) <\$> [2,5,10] <*> [8,10,11][55,80,100,110] （::=型注釈,ｐ３０参照）
23. 23. アプリカティブファンクター例３：IO Applicative Functorinstance Applicative IO where pure = return a <*> b = do f <- a x <- b return (f x)ghci> (++) <\$> getLine <*> getLinehgoaihgolk"hgoaihgolk"
24. 24. アプリカティブファンクター例４：((->) r) Applicative Functorinstance 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) \$ 5508(ここで: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. 25. アプリカティブファンクター例５：ZipList Applicative Functorinstance Applicative ZipList where pure x = ZipList (repeat x) ZipList fs <*> ZipList xs = ZipList (zipWith (f x -> f x) fs xs)・[]の<*>は可能な組み合わせすべてを結果に出す・ZipListの<*>はリストの個々の函数を対応する位置の 値に適用して結果に出す・ZipListをアプリカティブ・スタイルで使えばzipWith 函数群を使う必要がない
26. 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. 27. アプリカティブの便利な函数達Control.Applicative内には<\$>の他にもliftA2::(Applicative f) => (a->b->c) -> f a -> f b -> f cliftA2 f a b = f <\$> a <*> bやその他様々有用な函数（<\$,<**>,liftA3..)が存在また、ユーザ定義により(<*),(*>),等の函数も使えるようになるらしい。詳しくは以下URLを参照http://www.haskell.org/ghc/docs/6.12.1/html/libraries/base/Control-Applicative.html
28. 28. アプリカティブの便利な函数達他にも自分で便利な函数を作れるsequenceA :: (Applicative f) => [f a] -> f [a]sequenceA [] = pure []sequenceA (x:xs) = (:) <\$> x <*> sequenceA xsghci> sequenceA [Just 1,Just 2]Just [1,2]ghci> sequenceA [(>4),(<10),odd] 7[True,True,True]ghci> sequenceA [[1,2],[3,4],[5,6]][[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]ghci> sequenceA [getLine,getLine]hogehogemogemoge["hogehoge","mogemoge"]下２つは(:) <\$> [1,2] <*> ((:) <\$> [3,4] <*> [5,6])などと分解してみると結果の理由が理解しやすい