Haskellの記事です。
Applicativeを勉強していて、このブログを読んだ。
Applicative勉強中
2008年の記事なんで、何周周回遅れだよ。(´・ω・`)
とかは、置いといて、記事中に、こんなコード。
ap :: (Monad m) => m (a -> b) -> m a -> m b ap = liftM2 id liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) }
liftM2にidを適用することで、
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
が
ap :: (Monad m) => m (a -> b) -> m a -> m b
になるといっている。何とも不思議。
元記事中でも、この現象の不思議について解説しているんだけど。
自分なりに、理解した方法で説明をこころみてみる。
まず、idだが。
id :: a -> a
こんな関数だ。aを取ってaを返す。この子必要な子??
と、誰しもが1回は疑問に思うはず。しかし、なかなか賢い子なので、侮ってはいけない。(´・ω・`)
さて、これをliftM2に適用するわけだが。
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
まず、引数の数が違うしっ。こんなの入んない。(´;ω;`)
と、くじけてはいけない。痛いのは最初だけだ。
これを何とか入れてみようと、十代の熱っぽい視線でまじまじと見つめていると・・・。
何か見えてきた・・・。 (;゜д゜)
id :: a -> a のaは、型引数なので何でも良い。
aは、aは、(a2 -> r)でも良い。
(a1 -> a2 -> r)を、((a2 -> r) -> a2 -> r)と解釈すのは自由だ。
とすると、liftM2は、こういう風にも解釈できるよね。
-- a1の型を(a2 -> r)とする liftM2 :: (Monad m) => ((a2 -> r) -> a2 -> r) -> m (a2 -> r) -> m a2 -> m r
そうすると、id (a2 -> r) -> (a2 -> r)を適用できるではないか!(*゚Θ゚)ノ
実際に、liftM2 idの型をghciで調べる。
:t (listM2 id) (liftM2 id) :: Monad m => m (a2 -> r) -> m a2 -> m r
キタ━━━━ヽ(゜∀゜ )ノ━━━━!!!!
ap :: (Monad m) => m (a -> b) -> m a -> m b
これと、同じ型になった!
と、言うことで、idってすごいねっ。おもしろいねっていう話でした。