『プログラミングHaskell』を読み終えてから,次はどこへ向おうかと考えたところ,『Real World Haskell―実戦で学ぶ関数型言語プログラミング』を向いていました。まだHaskellの魅力を語れるほどの力はありませんが,何かHaskellの不思議な魅力にすっかり惹きつけられてしまったようです。
『プログラミングHaskell』と比べて,分厚いので最後まで読み終えることは出来ないかもしれませんが,興味の向くまま読み進めてみようと思います。
1章 始めましょう
2章 型と関数
3章 型を定義し,関数を単純化する
練習問題をすべて解いていませんが,3章まで読んでみました。
3章の練習問題に次のような問題があります。
3. リストの平均値を計算する関数を書きなさい。
ヒントに,fromIntegral関数を使うとあるので,以下のように作ってみました。
average xs = sum xs / fromIntegral (length xs)
実行すると,
Main> average [1,2,3,4]
2.5
ちゃんと答えがでるのですが,fromIntegralが気になります。
試しに,
Main> 10/4
2.5
とやってみたところ,ちゃんと答えが出ます。fromIntegralは,整数から浮動小数点に変換する関数みたいですが,分母が整数でも計算出来ていることから,fromIntegralは不要に思えます。以下のように変更して,
average xs = sum xs / (length xs)
試そうとするとエラーが出ますね…。10/4がOKで,上記がエラー。なんだか不思議です。
追記(2010/01/31)
haskell-jpで,非常に丁寧に教えていただきました。謎が解けて,すっきりした気分です。
Main> 10/4
2.5
は,整数型で実行されているように見えますが,実はDouble型。インタプリタを電卓代わりに使うとき,いちいち型を指定するのは面倒なので,Defaultingという仕組みがあるそうです。これは,ある型クラスに対して,デフォルトの型を決めてとりあえずそれでやりましょうという仕組みのこと。
たとえば,
- (Num a) => a という型の値は,このDefaultingでInteger
- (Fractional t) => t という型の値は,DefaultingでDouble
になります。
ということで,インタプリタで10/4を実行すると,10や4はDoubleにDefaultingされ,(/) :: Double -> Double -> Double が決まり,2.5がDoubleとして出てきます。
しかし,一方でDefaultingはある意味,静的型付けのうまみを捨ててしまうことにもなります。Defaultingを警告するオプションがコンパイラについています。
$ ghci -fwarn-type-defaults
Prelude> 10/4
:1:0:
Warning: Defaulting the following constraint(s) to type `Double'
`Fractional t' arising from a use of `/' at:1:0-3
In the expression: 10 / 4
In the definition of `it': it = 10 / 4
:1:0:
Warning: Defaulting the following constraint(s) to type `Double'
`Fractional t' arising from a use of `/' at:1:0-3
In the expression: 10 / 4
In the definition of `it': it = 10 / 4
2.5