2020/05/08

RustとHaskellを比較してみる

traitとtype class

あくまでど素人の考えですが、RustとHaskellは似ているのかなと思うところがありました。それはRustのtraitとHaskellのtype classです。

Rustにはi32とかcharとかがあり、HaskellにはIntとかCharとか、それぞれ基本的な型がありますが、それらに様々な機能を持たせるものとしてtraitとtype classがあって、例えばRustのi32AddEqOrdなどの多くのtraitが実装されています。これらが実装されているおかげで、四則演算や比較などができるのですが、Haskellも似たような感じになっていました。

たとえばHaskellのghciで以下のようにやってみると、


Prelude> :t 1
1 :: Num p => p

と表示されます。

このNumというものがtype classと呼ばれるもので、これが実装されていることで、加減乗の計算・絶対値などを扱うことが可能になっているようです。どのような機能を持っているか調べるにはHoogleというHaskell専用の検索エンジンみたいなものがあり、そこから「Prelude」で検索し、調べることができました。コードを見てRustと比較してみると、


class Num a where
    (+), (-), (*) :: a -> a -> a
    negate        :: a -> a
    abs           :: a -> a
    signum        :: a -> a
    fromInteger   :: Integer -> a
    .
    .
    .
    .

とあり、どうやらこの部分がRustのtraitと同じ感じで、


instance Num Int where
    .
    .
    .
    .

の部分がRustのimpl Int for Num {}と同じような感じに見えました。

Fizzbuzzプログラムを例にtype classを見てみます。まず前回のFizzbuzzプログラムをちょっと違った感じで書いてみます。


fizzbuzz n
    | mod n 15 == 0 = "Fizzbuzz"
    | mod n 5 == 0  = "Buzz"
    | mod n 3 == 0  = "Fizz"
    | otherwise = show n

この関数の型をghciで調べてみます。


*Main> :t fizzbuzz
fizzbuzz :: (Integral a, Show a) => a -> [Char]

となりました。

ここで出てくる(Integral a, Show a) => aというところにtype classが出てきています。これは引数の型に制約を設けています、ということを表しているようです。型aIntegralShowの両方を満たすものに限られる、ということになります。Integralmodができるものという制約をつけ、Showは文字列として表せるものという制約をつける、といった感じのようです。したがって、前回の記事でのFizzbuzzで書いたfizzbuzz :: Int -> Stringは、ユルユルの大雑把すぎる型アノテーション?であることが発覚しました。(ただただ勉強不足)

しかし、なんとも記号が多いこと。これは中々大変な言語なような気が致します。Rustの方が分かりやすいのじゃないか……なんて思うのですが、何事も継続、勉強です。ゆるゆる慣れていきます。