C#の型システムには、型クラスをインターフェイスとして適切に実装するために必要ないくつかの機能がありません。
あなたの例から始めましょうが、キーは、タイプクラスが何であり何をするのかについてのより完全な説明を示しており、それらをC#ビットにマップしようとしています。
class Functor f where
fmap :: (a -> b) -> f a -> f b
これは、型クラス定義、またはインターフェースに類似しています。次に、型の定義と、その型クラスの実装を見てみましょう。
data Awesome a = Awesome a a
instance Functor Awesome where
fmap f (Awesome a1 a2) = Awesome (f a1) (f a2)
これで、インターフェイスでは持ち得ない型クラスの1つの明確な事実を非常に明らかに見ることができます。型クラスの実装は、型の定義の一部ではありません。C#では、インターフェイスを実装するには、それを実装する型の定義の一部としてインターフェイスを実装する必要があります。これは、自分では実装していない型のインターフェイスを実装できないことを意味しますが、Haskellでは、アクセスできる型の型クラスを実装できます。
それはおそらくすぐに最大になりますが、別のかなり大きな違いがあり、C#の同等の機能が実際にはほとんど機能しないため、質問で触れています。ポリモーフィズムについてです。また、Haskellでは、特に実存型やジェネリックADTなどの他のGHC拡張機能のジェネリック性の量を調べ始めたときに、まったく翻訳されないタイプクラスを使用して、比較的一般的なことを行うことができます。
Haskellを使用すると、ファンクターを定義できます
data List a = List a (List a) | Terminal
data Tree a = Tree val (Tree a) (Tree a) | Terminal
instance Functor List where
fmap :: (a -> b) -> List a -> List b
fmap f (List a Terminal) = List (f a) Terminal
fmap f (List a rest) = List (f a) (fmap f rest)
instance Functor Tree where
fmap :: (a -> b) -> Tree a -> Tree b
fmap f (Tree val Terminal Terminal) = Tree (f val) Terminal Terminal
fmap f (Tree val Terminal right) = Tree (f val) Terminal (fmap f right)
fmap f (Tree val left Terminal) = Tree (f val) (fmap f left) Terminal
fmap f (Tree val left right) = Tree (f val) (fmap f left) (fmap f right)
次に、消費時に関数を使用できます。
mapsSomething :: Functor f, Show a => f a -> f String
mapsSomething rar = fmap show rar
ここに問題があります。C#では、この関数をどのように記述しますか?
public Tree<a> : Functor<a>
{
public a Val { get; set; }
public Tree<a> Left { get; set; }
public Tree<a> Right { get; set; }
public Functor<b> fmap<b>(Func<a,b> f)
{
return new Tree<b>
{
Val = f(val),
Left = Left.fmap(f);
Right = Right.fmap(f);
};
}
}
public string Show<a>(Showwable<a> ror)
{
return ror.Show();
}
public Functor<String> mapsSomething<a,b>(Functor<a> rar) where a : Showwable<b>
{
return rar.fmap(Show<b>);
}
C#バージョンにはいくつか問題があります.1つ<b>
は、私がそこにいたように修飾子を使用できるかどうかさえ確信していませんが、それなしでは適切にディスパッチされないことは確かですShow<>
(お気軽に試してくださいコンパイルして調べます;しませんでした)。
ただし、ここでの大きな問題は、上記のHaskellとは異なり、Terminal
s#を型の一部として定義し、型の代わりに使用できることです。これは、C#が適切なパラメトリック多型を欠いているためです(相互運用を試みるとすぐに明らかになります) F#with C#)右または左がTerminal
s かどうかを明確または明確に区別することはできません。できるのはuse null
だけですが、値の型を作成しようとしている場合、Functor
またはEither
両方とも値を保持する2つの型を区別する場合はどうでしょうか。今、あなたはあなたの差別をモデル化するためにチェックして切り替えるために1つのタイプを使用し、2つの異なる値を持っている必要がありますか?
適切な合計型、ユニオン型、ADT、それらを呼び出したいものの欠如は、タイプクラスがあなたに与えるものの多くを失います。 .NETの基礎となる型システムには、このような概念はありません。