第42回 Haskellのクラスについて調べる

Haskellのクラス

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"