我一直在用C#编程,但对其类型系统的局限性感到沮丧。我了解到Scala的第一件事是Scala具有更高的泛型。但即使在我看过许多文章、博客条目和问题之后,我仍然不确定什么是高级泛型。无论如何,我写了一些编译良好的 Scala 代码,这个代码段使用更高的种类吗?
abstract class Descrip [T <: DTypes, GeomT[_ <: DTypes] <: GeomBase[_]](newGeom: NewGeom[GeomT])
{
type GeomType = GeomT[T]
val geomM: GeomT[T] = newGeom.apply[T]()
}
然后我想也许我已经在使用更高种类的泛型了。据我所知,我是这样,但是当我现在理解它时,在我甚至听说过 Scala 之前,我已经很高兴地在 C# 中使用高级类型。这个狙击手使用更高种类的类型吗?
namespace ConsoleApplication3
{
class Class1<T>
{
List<List<T>> listlist;
}
}
因此,为了避免进一步的混淆,我认为澄清Java,C#和Scala中的每一个在高级类型,通配符和使用开放/部分开放类型方面允许的内容是有用的。由于C#和Scala之间的主要区别似乎是Scala允许通配符和开放类型,而C#没有通配符,并且要求在使用前关闭所有泛型类型。我知道它们有些不同,但我认为将这些功能的存在与C++模板中的等效功能联系起来会很有用。
那么以下正确吗?此表已针对阿列克谢的答案进行了更正
Lang: Higher-kind Wild-card Open-types
Scala yes yes yes
C# no no no
Java no yes no
C++ yes yes yes
这是高级类型不是:
不。高等类型是这样的
class Class1<T>
{
T<String> foo; // won't compile in actual C#
}
即,其参数本身必须是泛型的泛型类型。请注意,在此示例中,Class1<IList>
应编译,但不应编译Class1<String>
或Class1<IDictionary>
。
似乎你需要了解什么是高级类型,以及为什么它们有用。
考虑以下接口(Java,F<X,Y>
用作闭包替换):
interface ListFun {
public <A,B> List<B> fmap(F<A,B> fn, List<A> list);
}
interface SetFun {
public <A,B> Set<B> fmap(F<A,B> fn, Set<A> set);
}
这些接口看起来很有用,因为它们为集合定义了一种"转换"(这称为"函子")。但它们看起来很像代码重复。但是你不能写一个"统一"的接口,无论是用Java还是C#。
它应该是什么样子的?你会很想写这样的东西
interface Fun<X> {
public <A,B> X<B> fmap(F<A,B> fn, X<A> col);
}
class ListFun implements Fun<List> {...}
但是X<A>
在Java或C#中是不允许的,如果X
不是像List
这样的固定类型,而是一个类型参数。但是,如果以某种方式允许这种抽象(如在 Scala 或 Haskell 中),你就会有更高的种类类型(或"高阶类型多态性",术语仍然模糊不清)。以下是 Scala 特征和一个实现:
trait Fun[X[_]] {
def fmap[A,B](fn: A => B, col:X[A]):X[B]
}
class ListFun extends Fun[List]{
def fmap[A,B](fn: A => B, list: List[A]) = list.map(fn)
}
这是基本思想。通常你不会经常需要这些东西,但是当你需要它时,它可以非常有用。