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)
이제 인터페이스로는 가질 수없는 타입 클래스의 한 가지 분명한 사실을 볼 수 있습니다 . 형식 클래스의 구현은 형식 정의의 일부가 아닙니다. C #에서 인터페이스를 구현하려면 인터페이스를 구현하는 유형 정의의 일부로 인터페이스를 구현해야합니다. 즉, 자신이 구현하지 않은 유형에 대한 인터페이스를 구현할 수 없지만 Haskell에서는 액세스 할 수있는 모든 유형에 대한 유형 클래스를 구현할 수 있습니다.
그것은 아마도 가장 큰 것일 수도 있지만 C #과 동등한 것을 실제로 작동시키지 않는 상당히 중요한 또 다른 차이점이 있습니다. 다형성에 관한 것입니다. 또한 Haskell을 사용하면 기존 유형 또는 일반 ADT와 같은 다른 GHC 확장에서 일반화의 양을 볼 때 특히 번역하지 않는 유형 클래스로 할 수있는 비교적 일반적인 일이 있습니다.
하스켈을 사용하면 펑터를 정의 할 수 있습니다.
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 # 버전과 함께 몇 가지의 잘못은 내가 당신이 사용 할 수도 확실하지 않다 한 가지, 거기에 <b>내가 거기처럼 규정 만하지 않고 내가 생각 이 파견하지 않을 특정 Show<>(시도 주시기 적절하게 알아 내기 위해 컴파일하십시오.
그러나 여기서 더 큰 문제는 위의 Haskell과 달리 Terminal유형의 일부로 정의 된 다음 유형 대신 사용할 수 있다는 것입니다 .C #에 적절한 매개 변수 다형성이 부족하기 때문에 (상호 작용하려고하자마자 명백해집니다) F # with C #)를 사용하면 Right 또는 Left가 Terminals 인지 명확하거나 명확하게 구분할 수 없습니다 . 최선의 방법은을 사용하는 것입니다 null. 그러나 값 유형을 만들려고 Functor하거나 Either값을 전달하는 두 가지 유형을 구별하려는 경우 어떻게해야합니까? 이제 하나의 유형을 사용하고 두 가지 다른 값을 사용하여 차별을 모델링하기 위해 확인하고 전환해야합니까?
적절한 합계 유형, 공용체 유형, ADT가 없으면 호출하려는 유형에 관계없이 하루 종일 여러 유형 (생성자)을 단일 유형으로 처리 할 수 있기 때문에 유형 클래스에서 많은 것을 포기하게됩니다. .NET의 기본 유형 시스템에는 그러한 개념이 없습니다.