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还允许您使用一些相对通用的类型来处理类型类,而这些类不会完全转换,尤其是当您开始查看存在性类型或其他GHC扩展(如通用ADT)中的通用性时。
您会发现,使用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#版本,有一件事我甚至不能肯定它可以让你使用<b>
像我一样有资格,但没有它,我是一定不会派遣Show<>
适当地(随意尝试并编译以找出答案;我没有)。
但是,这里更大的问题是,与上面在Haskell中不同的是,我们将Terminal
s定义为类型的一部分,然后代替类型使用,这是由于C#缺乏适当的参数多态性(一旦尝试进行互操作,这一点就变得非常明显) F#和C#),您无法清楚或清楚地区分Right或Left是Terminal
s。最好的办法就是使用use null
,但是如果您尝试将值类型设为a,Functor
或者Either
要区分两种都带有值的类型该怎么办?现在,您必须使用一种类型,并使用两个不同的值来检查并在之间建立模型以进行区分?
缺少适当的总和类型,联合类型,ADT,无论您想称呼它们多少,实际上都会使很多类型类不起作用,因为归根结底,它们让您将多个类型(构造函数)视为一个类型, .NET的基础类型系统根本没有这样的概念。