通配符模式覆盖多态变体的子类型约束

时间:2017-11-09 21:45:39

标签: types ocaml type-inference subtyping polymorphic-variants

鉴于这些类型

let pp: [< b] -> string =
  function | `A -> "A"
           | `B -> "B"
           | `C -> "C"

和这个功能

a

应用let a: a = `A let _ = pp a 类型的值可以正常工作,如预期的那样:

let pp: [< b] -> string =
  function | `A -> "A"
           | `B -> "B"
           | _ -> "?"

但是,如果修改该函数以包含通配符模式

let _ = pp a

即使其他所有内容保持不变,它现在也会产生以下错误(在.docx上):

  

此表达式具有类型b - &gt;字符串但表达式需要类型a - &gt; 'a B型= [`A | `B]与类型a = [`A]不兼容第二种变体类型不允许标记`B

问题:

  1. 为什么它不再能够接受子类型?我理解通配符意味着它现在可以接受超类型,但这不应该意味着它必须。
  2. 有没有办法解决这个问题,以避免必须列举一百万个不相关的变种?

2 个答案:

答案 0 :(得分:7)

潜在的问题是

的类型
let pp= function
| `A -> "A"
| `B -> "B"
| _ -> "?"

被认为是[> `A| `B] -> string而不是[< `A| `B | ... ] -> string(其中...代表任何构造函数)。答案是,这是一种设计选择,也是假阳性和假阴性之间妥协的问题:https://www.math.nagoya-u.ac.jp/~garrigue/papers/matching.pdf

更确切地说,第二种类型被认为太弱,因为它太容易丢失`A中存在`Bpp的信息。例如,请考虑以下代码,其中`b是拼写错误,应该是`B

let restrict (`A | `b) = ()
let dual x = restrict x, pp x

目前,此代码以

失败
  

错误:此表达式的类型为[&lt; `A | `b]但预计会有表达   类型[&gt; `A | `B]
  第一种变体类型不允许标记“B

此时,如果`b是拼写错误,则可以在此处发现错误。如果pp已键入[< `A|`B |..],则双重类型将默认限制为[`A] -> unit * string,无法捕获此错误。此外,对于当前的输入,如果`b不是拼写错误,则完全有可能通过添加一些强制使dual有效

let dual x = restrict x, pp (x:[`A]:>[>`A]);;
(* or *)
let dual x = restrict x, (pp:>[`A] -> _) x

明确指出restrictpp适用于不同的多态变体集。

答案 1 :(得分:1)

pp的第二个版本的类型为[< b > `A `B ] -> string。换句话说,`A`B必须出现在该类型中。我想,如果您想要将值与`B进行比较,那么`B应该出现在值的类型中,这似乎是合理的。

您可以撰写pp (a :> b)