Haskellの実験メモです。
Haskellの型クラスはオブジェクト指向言語のインターフェースと似ている面があります。特にF#のインターフェースは書式まで似ているため比較してみます。ただし似ているのは定義だけで、実装や呼び出し方法はあまり似ていません。
定義
書式がとても似ています。
Haskell:型クラス
class Foo a where
foo :: a -> String
F#:インターフェース
type Foo<'a> =
abstract foo: 'a -> string
実装
Haskellの型クラスは、対象となる型とは分離した形で型クラスのインスタンスを作成します。
Haskell
instance (Num a, Eq a) => Foo a where
foo 1 = "bar"
foo _ = "?"
instance Foo String where
foo "1" = "baz"
foo _ = "?"
F#はあくまでオブジェクト指向的な意味合いでのインターフェースなので、クラスを定義して実装します。
F#
type FooInt() =
interface Foo<int> with
member x.foo a =
match a with
| 1 -> "bar"
| _ -> "?"
type FooString() =
interface Foo<string> with
member x.foo a =
match a with
| "1" -> "baz"
| _ -> "?"
呼び出し
Haskellの型クラスの関数はそのまま呼び出せます。
Haskell
main = do
putStrLn $ foo 1
putStrLn $ foo "1"
F#ではクラスのインスタンスを作成して、インターフェースにキャストして呼び出します。
F#
printfn "%s" <| (FooInt () :> Foo<int> ).foo 1
printfn "%s" <| (FooString() :> Foo<string>).foo "1"
そもそも概念が異なるので、同列に比較するのは無理があります。
メソッドのオーバーロード
F#ではメソッドのオーバーロードが可能です。今回の例ではこちらを使った方が簡単です。
F#
type Foo =
static member foo a =
match a with
| 1 -> "bar"
| _ -> "?"
static member foo a =
match a with
| "1" -> "baz"
| _ -> "?"
printfn "%s" <| Foo.foo 1
printfn "%s" <| Foo.foo "1"
F#では型クラスに相当するものはありませんが、必要に応じてインターフェースかオーバーロードを使い分けることになりそうです。