第42回 Haskellのクラスについて調べる
自分でクラスを作る
Haskellでいうクラスとは、「引数の型によって動作を変えるような関数」を集めたものらしい。
-------------------------------------------------------------------- -- クラス定義 -------------------------------------------------------------------- class Hoge a where foo :: a -> String -- fooは何かを受け取ってStringとして返す
これはひとつしか関数を持っていないHogeというクラスである。
fooはどんなものであるかその型が書かれてある。
ではクラスを作ったあとに何をするかというと、今このクラスにはfooの型しかかれていないので、
どこかにfooの実装を書かないといけない。
おや!これってJavaのインタフェースみたいなものなんですかね!?(あとで別で実装するというところ)
いや!これってJavaのオーバーロードみたいなものなんですかね!?(引数の型によって動作を変える関数というところ)
fooを実装
fooを実装する前に、Javaのimplementsするクラスみたいにまず型を作ってやらないといけない。
今回は次の2つの型を自分で作ってみた。
-------------------------------------------------------------------- -- 型定義 -------------------------------------------------------------------- data D = D String -- Stringを1つもつDという型を定義 data DD = DD String String -- Stringを2つもつDDという型を定義
型ができたので、この型の値を持った変数を作ろう。
たぶんHaskell的には変数ではないのだろうけど、なんと呼べばよいのかわからないので、変数と呼ぶことにする。
-------------------------------------------------------------------- -- 変数定義 -------------------------------------------------------------------- d = D "AAA" -- "AAA"という値を持つD型をdに代入 dd = DD "BBB" "CCC" -- "BBB","CCC"という値を持つDDをddに代入
このDとDDにHogeをimplementsする....ではなくて、
このDとDDをHogeのinstanceとする。
書き方は、
-------------------------------------------------------------------- -- DはHogeのインスタンス -------------------------------------------------------------------- instance Hoge D where foo(D x) = "> " ++ x -------------------------------------------------------------------- -- DDもHogeのインスタンス -------------------------------------------------------------------- instance Hoge DD where foo(DD x y) = "> " ++ x ++ y
これでD用のfooとDD用のfooが実装された。
では、mainで実行してみよう。
-------------------------------------------------------------------- -- main -------------------------------------------------------------------- main = do{ print( foo d ); print( foo dd); }
d には "AAA"
dd には "BBB","CCC"が入っているので、
結果は、
"> AAA" "> BBBCCC"
となる。
全体のプログラムを載せておく。
-------------------------------------------------------------------- -- クラス定義 -------------------------------------------------------------------- class Hoge a where foo :: a -> String -- fooは何かを受け取ってStringとして返す -------------------------------------------------------------------- -- 型定義 -------------------------------------------------------------------- data D = D String -- Stringを1つもつDという型を定義 data DD = DD String String -- Stringを2つもつDDという型を定義 -------------------------------------------------------------------- -- 変数定義 -------------------------------------------------------------------- d = D "AAA" -- "AAA"という値を持つD型をdに代入 dd = DD "BBB" "CCC" -- "BBB","CCC"という値を持つDDをddに代入 -------------------------------------------------------------------- -- DはHogeのインスタンス -------------------------------------------------------------------- instance Hoge D where foo(D x) = "> " ++ x -------------------------------------------------------------------- -- DDもHogeのインスタンス -------------------------------------------------------------------- instance Hoge DD where foo(DD x y) = "> " ++ x ++ y -------------------------------------------------------------------- -- main -------------------------------------------------------------------- main = do{ print( foo d ); print( foo dd); }
Showクラス
HaskellにはShowクラスというのがあって、
これは色んな型を文字列に変換できるみたい。
でも色んな型を文字列に変換できるっていっても、
型がこれだけついている言語では、型ごとによって変換の仕組みを実装する必要があるみたい。
だから色々な型はShowクラスのインスタンスとなって、変換の仕組みを実装する。
すこし違うがイメージ的にはJavaの各クラスで .toString()を実装するのに似ているのだろうか?
でもって instanceの別の書き方にderivingというのがあって、
よくわからないのだがこれは明示的なことはやってくれるらしい。
例えば次のソースはエラーが出るが、
-------------------------------------------------------------------- -- 型定義 -------------------------------------------------------------------- data DD = DD String String -- Stringを2つもつDDという型を定義 -------------------------------------------------------------------- -- 変数定義 -------------------------------------------------------------------- dd = DD "BBB" "CCC" -- "BBB","CCC"という値を持つDDをddに代入 -------------------------------------------------------------------- -- main -------------------------------------------------------------------- main = do{ print( dd ) }
DDがShowをderivingするとうまくいく。
-------------------------------------------------------------------- -- 型定義 -------------------------------------------------------------------- data DD = DD String String deriving(Show) -- Stringを2つもつDDという型を定義はShowをderiving -------------------------------------------------------------------- -- 変数定義 -------------------------------------------------------------------- dd = DD "BBB" "CCC" -- "BBB","CCC"という値を持つDDをddに代入 -------------------------------------------------------------------- -- main -------------------------------------------------------------------- main = do{ print( dd ) }
結果:DD "BBB" "CCC"