Types 参数多态性是否与arity上的分派相同?

Types 参数多态性是否与arity上的分派相同?,types,programming-languages,type-theory,Types,Programming Languages,Type Theory,如果参数多态性在不依赖于参数类型的情况下进行调度,那么除了arity之外,还有什么可以调度的呢?如果不一样,有人能提供一个反例吗? 参数多态性背后的思想是您不需要分派—参数多态性函数对于所有输入类型的行为都是相同的。让我们考虑一个非常简单的例子(我将使用Haskel1): id x=x 这定义了一个名为id的函数,它接受一个参数x,并返回它。这是身份功能;它没有任何作用。现在,id应该有什么类型?它肯定是一个函数,因此对于某些input和output,它将具有类型input->output。我

如果参数多态性在不依赖于参数类型的情况下进行调度,那么除了arity之外,还有什么可以调度的呢?如果不一样,有人能提供一个反例吗?

参数多态性背后的思想是您不需要分派—参数多态性函数对于所有输入类型的行为都是相同的。让我们考虑一个非常简单的例子(我将使用Haskel1):

id x=x
这定义了一个名为
id
的函数,它接受一个参数
x
,并返回它。这是身份功能;它没有任何作用。现在,
id
应该有什么类型?它肯定是一个函数,因此对于某些
input
output
,它将具有类型
input->output
。我们可以说,
id
具有类型
Int->Int
;然后
id3
将计算为
3
,但是
idtrue
不会进行打字检查,这看起来很愚蠢。说
id::Bool->Bool
也没什么好处;问题反过来了。我们知道,对于
id
,输入的类型无关紧要
id
忽略该结构,只传递值。因此,对于任何类型
a
id
都有类型
a->a
,我们可以明确地写下:

id::a->a
id x=x
在Haskell中,类型中的小写标识符是通用的量化变量。上面的签名与我编写的
id::forall a相同。a->a
,除了显式地为all编写
仅对某些语言扩展有效

标识函数是参数多态函数的最简单示例,它强调了参数函数只是传递数据的思想。他们无法对数据进行任何检查

让我们考虑一个稍微有趣的功能:列表反转。在Haskell中,某种类型的

a
列表被写入
[a]
,因此
反向
函数被禁用

反向::[a]->[a]
反向[]=[]
反向(x:xs)=反向xs++[x]
--`x:xs`是第一个元素为`x`的列表,第二个元素为
--`xs`;`++`是列表附加运算符。
reverse
函数对列表中的元素进行洗牌,但它从不操纵它们(因此也从不“分派”它们)。因此,
reverse
知道它必须获取并返回某个内容的列表,但它不关心该内容是什么

参数多态性的最后一个例子是
map
函数。此函数接受一个函数
f
和一个列表,并将该函数应用于列表中的每个元素。这个描述告诉我们,我们不关心函数的输入或输出类型,也不关心输入列表的类型,但它们必须适当匹配。因此,我们有

map::(a->b)->[a]->[b]
映射f[]=[]
映射f(x:xs)=fx:mapfxs
--在Haskell中,函数应用程序是空白的,所以'mapfxs'类似于
--类C语言中的map(f,xs)`。
请注意,传入函数的输入(分别输出)类型和输入(分别输出)列表的元素类型必须匹配;然而,输入和输出类型可以彼此不同,我们不在乎

参数多态性与亚型 您可以在注释中询问参数化函数是否只接受top类型的值。答案是否定的:子类型完全独立于参数多态性。Haskell根本没有任何子类型的概念:一个
Int
就是一个
Int
,一个
Bool
就是一个
Bool
,两者永远不会相遇。在Java中,您既有泛型也有子类型,但这两个特性在语义上是不相关的(除非您使用
形式的有界多态性,但这更像是一种特殊多态性,我将在下面讨论)。参数多态实际上就是它所说的:接受任何类型的函数。这与接受top类型并依赖于包容/隐式向上转换的函数不同。考虑这一点的一种方法是,参数化函数接受一个附加参数:参数的类型。因此,您将使用
idint3
,而不是
id3
;而不是
id-True
,您将拥有
id-Bool-True
。在Haskell中,您永远不需要显式地执行此操作,因此没有语法。另一方面,在Java中,有时需要这样做,因此有一些语法反映了这一点,如
Collections.emptyList()


特殊多态性 参数多态性通常与各种形式的特殊多态性形成对比:多态性允许一个函数在不同类型下以不同的方式运行。这就是“调度”出现的地方;参数多态性与一致性有关,而特殊多态性与差异有关。有时,您不希望函数在每种类型上都以相同的方式运行

标准的类似Java的面向对象子类型多态性(正式称为标称子类型)就是一个例子;例如,在Java中,
boolean Object.equals(Object)
方法使用子类型多态性对其第一个参数进行分派,并返回适当的结果。很明显,您不希望平等是参数化的;您不能编写一个函数来精确比较字符串和整数的相等性!但是,请注意,
.equals
还使用
instanceof
对参数的运行时类型执行“typecase”检查;
int Object.hashCode()
方法是纯子类型多态方法的一个示例

Haskell使用另一种称为类型类多态性的方法来
public static <T> T id(T t) { return t; }