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