top page > computer > haskell > web_lecture > for_programmer > typeclass_default.html
更新日:
文責: 重城良国

クラス関数のデフォルト定義

(工事中 60%)

成長する

grow.hs

成長することと足し合わせることができるという性質を表す型クラスGrowableを考えよう。

class Growable g where
grow :: g -> Maybe g
add :: g -> g -> g

関数growはすでに成長しきった値に対してはNothingを返すものとする。ある値を成長しきるまで成長させてそのあいだの値を足し合わせる関数が書ける。

growingSum :: Growable g => g -> g
growingSum g = case grow g of
Just g' -> g `add` growingSum g'
_ -> g

整数型をこのクラスのインスタンスにしてみよう。ここでは100に達したら成熟したものと考える。

instance Growable Int where
grow n
| n < 100 = Just $ n + 1
| otherwise = Nothing
add = (+)

このようにすると関数growingSumをInt型の値に対して適用することができる。

% ghci grow.hs
*Main> growingSum 0 :: Int
5050
*Main> growingSum 25 :: Int
4750

もっと効率的に

整数においてはgrowingSumは与えられた値から100まで1刻みで増加させていった総和だ。これはもっと効率的に計算できる。しかしgrowingSumを整数用にカスタマイズすることはできない。以下のようにgrowingSumをクラス関数にしてしまおう。

class Growable g where
grow :: g -> Maybe g
add :: g -> g -> g
growingSum :: g -> g

このようにすることで整数におけるgrowingSumを別個に定義することができる。しかし、整数以外の値に対してはもともとのgrowingSumを使いたいとする。このようなときデフォルト定義を使うことができる。class宣言のスコープのなかに関数growingSumのデフォルトの定義を置く。

growingSum g = case grow g of
Just g' -> g `add` growingSum g'
_ -> g

こうしておくとgrowingSumは明示的に定義されないかぎりデフォルトの定義が使われる。デフォルトの定義のままで試してみよう。

*Main> :reload
*Main> growingSum 0 :: Int
5050
*Main> growingSum 25 :: Int
4750

それでは整数用の特別な定義でおきかえてみる。Growableクラスへの型Intのインスタンス宣言のスコープ内に以下を書く。

growingSum n = (100 - n + 1) * (100 + n) `div` 2

このようにするとIntに対しては特別な定義が使われるようになる。

*Main> :reload
*Main> growingSum 0 :: Int
5050
*Main> growingSum 25 :: Int
4750

まとめ

クラス関数にはデフォルト定義を与えることができる。デフォルト定義のあるクラス関数は定義を省略することもできるし、効率等の関係で定義しなおすこともできる。

「仕様としての型クラス」へもどる 「ドリンクのサイズの例」へ

正当なCSSです! HTML5 Powered with CSS3 / styling, and Semantics