"True Polymorphism"的例子?(最好使用哈斯克尔)

Example of "True Polymorphism"? (Preferably, using Haskell)

本文关键字:哈斯克 Polymorphism True      更新时间:2023-10-16

我看过很多"真多态"的部分定义,例如这里和这里,但是我没有找到一个明确的例子来说明两个具体例子的区别。

我理解重载+操作符是某种形式的多态性,它在Haskell和c++中实现不同。有人能用两种语言的例子准确地说明它们的区别吗?

您要查找的术语是"参数多态性",这与"ad-hoc多态性"不同。

参数多态性的一个例子是Nothing的类型签名:
Nothing :: Maybe a

类型中的a可以是任何可能的类型,因为Nothing居住在所有Maybe中。我们说a是参数多态的,因为它可以是任何类型。

现在考虑这个类型:

Just 1 :: (Num b) => Maybe b

这次b不能是任何类型:它只能是Num的实例类型。我们说b是ad-hoc多态的,因为它可以是由Num类的实例给出的类型集合中的任何成员。

总结一下:

  • 参数多态性:可以是任何类型

  • Ad-hoc多态性:受类型类约束

您将经常遇到三种类型的多态性(使用c++和Haskell示例)。

参数多态性在函数语言中是类型系统的一个特征,其中函数的类型是在类型变量上量化的表达式。输入类型约束签名中的自由参数,签名决定输出类型。例如,map函数接受一个函数作为其第一个参数,该参数决定输入列表和输出列表的类型。

map :: (a -> b) -> [a] -> [b]

在类型理论中,签名通常写成:

 ∀ a. ∀ b. (a -> b) -> [a] -> [b]

c++可以通过模板实现参数多态性的效果,但在我看来,它非常脆弱(即导致模糊的编译错误),并且缺乏在现有函数式语言中发现的形式化:

template <class T>
T add(T a, T b) {
    return a+b;
}

Ad-hoc多态性是指具有相同名称的函数在使用不同类型签名"查看"时行为不同。在Haskell中,这是用类型类表示的。(+)的签名中的a类型被限制为实现Num类型类的类型。

(+) :: Num a => a -> a -> a
class Num a where
    (+) :: a -> a -> a
instance Num Int  where
    (+) = plusInt 

子类型多态性。Haskell中没有,但其他语言(Scala, ML)有子类型多态性。在面向对象语言中,这通常是一种语言特性,其中不同的对象实例实现具有相同名称的方法或属性调用,并根据对象模型的语义进行分派。例如在c++中:

class Animal {
public:
 virtual void speak() = 0;
};
class Cat : public Animal {
public:
 void speak() { 
    printf("Meow");
 }
};
class Dog : public Animal {
public:
 void speak() { 
    printf("Woof");
 }
};
关于多态性,要记住的是将核心思想与实现分开。例如,ad-hoc多态性与类型类不同,它只是它的一个表达式。