我在理解不同类型的多态性时遇到了问题,特别是在OCaml方面。我知道多态性允许OCaml中的多个类型表示为'a,但我不明白不同类型的多态性是什么。
如果有人可以用相对较低级别的语言给我一个解释,那就太棒了!
ad hoc,参数,包含/子类型
答案 0 :(得分:13)
这是近似值。
Ad-hoc多态性通常是指能够声明具有不同类型的相同名称(通常是函数),例如SML中的+ : int -> int -> int
和+ : float -> float -> float
。这些是不同的功能,它们可以以完全不同的方式起作用,但编译器或解释器根据上下文选择适当的功能。我想不出OCaml中任何ad-hoc多态性的例子。然而,它在C ++和Java中很常见。
参数多态是指单个函数可以使用任何类型的参数,因为它不会试图查看该参数的结构。例如,cons : 'a -> 'a list -> 'a list
能够将任何类型的值v
添加到相同类型的值列表中,因为cons
与v
的结构(布局)无关。 cons
是,或者它支持的操作。在C语言中,v
不需要“取消引用”指针,也不需要对v
执行任何特定于cons
实际类型的操作。请注意,与ad-hoc多态性不同,t
具有以对所有类型采取相同的方式。因此,参数和特殊多态性在某种程度上是彼此自然的“对立面”。参数多态性是OCaml中绝大多数多态性实例的原因。
子类型多态性是指您可以使用类型u
的值,其中值为t
的值。这可能是因为类型u
支持t
类型的所有操作,或者因为u
的结构可以在期望'A | 'B
的地方使用。这样的例子就是子类化(也许可以在车辆可以使用的任何地方使用总线)或多态变体(你可以使用'A | 'B | 'C
预期f : u -> int
。)
每条评论的编辑
但是,请注意,必须在OCaml中明确请求子类型。例如,如果您有一个函数v : t
,并且想要将其应用于t
,其中u
是f (v :> u)
的子类型,则必须编写{{1} }}。 (v :> u)
语法是类型强制。
OCaml还支持行多态,这是一种带约束的参数多态。如果f
代替f : #u -> int
(对象类型)或f : [< u] -> int
(对于多态变体),则#u
/ [< u]
语法表示类型变量,类似于'a
,但只能用u
的相应“子类型”替换(在限制意义上它们可以分别支持更多字段/更少的构造函数)。然后,您可以在没有强制的情况下执行f v
。对于涉及多态变体和对象的许多表达式,OCaml会自动推断使用行多态的类型,但如果要创建签名,则必须明确编写类型。
行多态性有更多用法和注意事项。我忽略了实际的行变量和附加语法,只描述了看似有限量化的东西(如Java泛型)。关于行多态性,其名称和/或形式主义的更详细和准确的讨论可能最好地保存用于单独的问题。
答案 1 :(得分:1)
我实际上并不认为这类问题特别适合Stack Overflow的优势。有关于类型的全书。事实上,我建议阅读皮尔斯的Types and Programming Languages,我发现这是非常有启发性和令人愉快的。
作为一个快速回答(主要基于我记得皮尔斯的内容:-),这里是我对这些条款的看法。
参数多态是指其中包含自由变量的类型,其中变量可以由任何类型替换。函数List.length
具有这样的类型,因为它可以找到任何列表的长度(无论元素的类型是什么)。
# List.length;;
- : 'a list -> int = <fun>
关于OCaml的一个奇妙的事情是它不仅支持这样的类型,而且推断它们。给定函数定义,OCaml推断函数的最通用的参数多态类型。
子类型是类型之间的关系。类型 T 是 U 类型的子类型,如果 T 的所有实例也是 U 的实例(但是不一定相反)。 OCaml支持子类型,也就是说,它允许程序将 T 类型的值视为其超类型 U 的值。但是,程序员必须明确地要求这样做。
# type ab = [ `A | `B ];;
type ab = [ `A | `B ]
# type abc = [`A | `B | `C ];;
type abc = [ `A | `B | `C ]
# let x : ab = `A;;
val x : ab = `A
# let y : abc = x;;
Error: This expression has type ab but an expression was expected
of type abc. The first variant type does not allow tag(s) `C
# let y : abc = (x :> abc);;
val y : abc = `A
在此示例中,类型类型ab
是类型abc
的子类型,x
类型为ab
。您可以将x
用作类型abc
的值,但必须使用:>
类型运算符显式转换。
Ad-hoc多态性是指程序员针对特定情况定义的多态性,而不是源自基本原则。 (或者至少它是我的意思,也许其他人使用不同的术语。)一个可能的例子是OO继承层次结构,其中对象状态的实际类型不需要以任何方式相关只要方法有适当的关系。
关于ad-hoc多态性(恕我直言)的关键观察是,它由程序员来完成。因此,它并不总是有效。这里基于基本原理的其他类型的多态实际上无法工作。使用复杂系统时,这是一种安慰的感觉。
答案 2 :(得分:0)
ident是多形的:
# let ident x = x;;
val ident : 'a -> 'a = <fun>
# ident 1;;
- : int = 1
# ident "ok";;
- : string = "ok"
# ident [];;
- : 'a list = []
# ident List.length;;
- : '_a list -> int = <fun>
# ident ident;;
- : '_a -> '_a = <fun>
折叠:
# open List;;
# fold_left (+) 0 [1;2;3];;
- : int = 6
# fold_left (^) "" ["1";"2";"3"];;
- : string = "123"
# fold_left (fun a (x,y) -> a+x*y) 0 [(1,2);(3,4);(5,6)];;
- : int = 44