2006-12-23
■ ($)と(.)の違いを考えてみた

Yet Another HaskellのExersize3.2の問題を解こうとしてはまりました
英語が苦手なので問題の意味がよく分かっていないかもしれませんがしていされたタプルからfstとsndで文字をとりだせと解釈した
指定されたタプルは
(1,'a'),"foo")
で、こんなかんじでやっってみた。
Prelude> let outOfChar = ( snd.fst t , snd t)
で、おこられた。
Prelude> outOfChar ((1,'a'),"foo")
<interactive>:1:11:
Couldn't match expected type `a1 -> (a, b)'
against inferred type `(a11, b1)'
In the expression: (1, 'a')
In the first argument of `outOfChar', namely `((1, 'a'), "foo")'
In the expression: outOfChar ((1, 'a'), "foo")
とりあえず、型をみると
Prelude> :t ( snd . fst) ( snd . fst) :: ((a, b), b1) -> b
あっていそうである。でも、何故はじかれるのだろう?
よくわからないので、(.)を($)にかえてみる。
Prelude> let outOfChar t = ( snd $ fst t , snd t)
Prelude> outOfChar ((1,'a'),"foo")
('a',"foo")
これは、大丈夫。(.)も($)もあとの関数に最初の関数をくっつけるものとしての認識だったのだが。
しばらく悩んでみると、関数の適用がHaskellでは最優先されるということを思い出す。なので、(.)を使った方は、
snd . (fst t)
と解釈されてしまい、失敗したのではないだろうか?これでは、fst t はaがかえってくることになるから、型エラーになっているのではないのか?($)の場合、適用した値(といっていいのだろうか?)がsndに渡されるので成功したのか。試しに、適用順を括弧でやってみる
Prelude> let outOfChar t = ( ((snd . fst) t) , snd t)
Prelude> outOfChar ((1,'a'),"foo")
('a',"foo")
成功した。
Prelude> let t =((1,'a'),"foo") Prelude> :t snd . fst t <interactive>:1:6: Couldn't match expected type `a -> (a1, b)' against inferred type `(Integer, Char)' In the second argument of `(.)', namely `fst t' Prelude> :t fst t fst t :: (Integer, Char) Prelude> :t snd snd :: (a, b) -> b Prelude> :t snd . fst snd . fst :: ((a, b), b1) -> b
snd .fst tのもとめられている、a -> (a1,b)は、どの部分の型なのだろうか?
なんとなく、こういうときの対処は、わかるようになったけど、どうもうまくつかめないなぁ。cでポインタにはまったときのような気分。
(.) :: (b -> c) -> (a -> b) -> a -> c
の a -> b がここでは a -> (a1, b) にあたるんではないかと。