我已经看到很多关于“真正的多态性”的部分定义,例如here和here但我无处可以通过两个具体的例子找到一个明显的差异示例。 / p>
我知道重载+
运算符是某种形式的多态,并且它在Haskell和C ++中的实现方式不同。有人能准确地说明两种语言中的例子有什么不同吗?
答案 0 :(得分:6)
您正在寻找的术语是“参数多态”,它与“ad-hoc多态”不同。
参数多态的一个例子是Nothing
的类型签名:
Nothing :: Maybe a
类型中的a
可以是任何可想到的类型,因为Nothing
居住在所有Maybe
中。我们说a
是参数多态的,因为它可以是任何类型。
现在考虑这种类型:
Just 1 :: (Num b) => Maybe b
这次b
不能是任何类型:它只能是Num
实例的类型。我们说b
是ad-hoc多态的,因为它可以是一组类型的任何成员,由Num
类的实例给出。
所以,回顾一下:
参数多态:可以是任何类型
Ad-hoc多态:由类型
答案 1 :(得分:3)
您经常会遇到三种类型的多态(使用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多态与type-classes不同,它只是它的一个表达式。