#let f = function `On -> 1 | `Off -> 0 | `Number n -> n;;
val f : [< `Number of int | `Off | `On ] -> int = <fun>
# List.map f [`On; `Off];;
- : int list = [1; 0]
[>`Off|`On] list 表示要匹配这个列表,你至少应该能够匹配 `Off 和 `On,且不带参数。 [<`On|`Off|`Number of int] 表示 f 可以应用于 `Off、`On(两者都不带参数)或 `Numbern,其中 n 是一个整数。变体类型中的 > 和 < 表明它们仍然可以被细化,要么通过定义更多标签,要么通过允许更少标签。因此,它们包含一个隐式类型变量。由于每个变体类型在整个类型中只出现一次,因此它们的隐式类型变量不会显示。
val f : ([> `A | `B | `C | `D ] as 'a) -> 'a = <fun>
# f `E;;
- : [> `A | `B | `C | `D | `E ] = `E
这里我们看到了两种现象。首先,由于这种匹配是开放的(最后一个情况捕获任何标签),我们得到了类型 [> `A | `B] 而不是在封闭匹配中得到 [< `A | `B]。然后,由于 x 是按原样返回的,所以输入和返回类型是相同的。符号 as 'a 表示这种类型共享。如果我们对 f 应用另一个标签 `E,它将被添加到列表中。
#let f1 = function `A x -> x = 1 | `B -> true | `C -> falselet f2 = function `A x -> x = "a" | `B -> true ;;
val f1 : [< `A of int | `B | `C ] -> bool = <fun> val f2 : [< `A of string | `B ] -> bool = <fun>
#let f x = f1 x && f2 x;;
val f : [< `A of string & int | `B ] -> bool = <fun>
这里 f1 和 f2 都接受变体标签 `A 和 `B,但 `A 的参数对于 f1 是 int,对于 f2 是 string。在 f 的类型中,只有 f1 接受的 `C 消失了,但是 `A 的两个参数类型都以 int & string 形式出现。这意味着,如果我们传递变体标签 `A 到 f,它的参数应该同时是 int 和 string。由于不存在这样的值,因此无法将 f 应用于 `A,而 `B 是唯一接受的输入。
#let num x = `Num x let eval1 eval (`Num x) = x letrec eval x = eval1 eval x ;;
val num : 'a -> [> `Num of 'a ] = <fun> val eval1 : 'a -> [< `Num of 'b ] -> 'b = <fun> val eval : [< `Num of 'a ] -> 'a = <fun>
#let plus x y = `Plus(x,y) let eval2 eval = function | `Plus(x,y) -> eval x + eval y | `Num _ as x -> eval1 eval x letrec eval x = eval2 eval x ;;
val plus : 'a -> 'b -> [> `Plus of 'a * 'b ] = <fun> val eval2 : ('a -> int) -> [< `Num of int | `Plus of 'a * 'a ] -> int = <fun> val eval : ([< `Num of int | `Plus of 'a * 'a ] as 'a) -> int = <fun>
为了更方便使用,您可以使用类型定义作为或模式的缩写。也就是说,如果您定义了 type myvariant = [`Tag1 of int | `Tag2 of bool],那么模式 #myvariant 等同于写 (`Tag1(_ : int) | `Tag2(_ : bool))。
这种缩写可以单独使用,
#let f = function | #myvariant -> "myvariant" | `Tag3 -> "Tag3";;
val f : [< `Tag1 of int | `Tag2 of bool | `Tag3 ] -> string = <fun>