セカイノカタチ

世界のカタチを探求するブログ。関数型言語に興味があり、HaskellやScalaを勉強中。最近はカメラの話題も多め

Haskellのidっておもしろい

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ってすごいねっ。おもしろいねっていう話でした。