什么时候双重强制有用?

时间:2017-06-09 06:04:29

标签: types ocaml coercion ocsigen

我偶然发现了OCaml中的以下编译消息:

This simple coercion was not fully general. Consider using a double coercion.

它发生在相当复杂的源代码中,但这是一个MNWE:

open Eliom_content.Html.D

let f_link s =
  let arg : Html_types.phrasing_without_interactive elt list = [pcdata "test"] in
  [ Raw.a ~a:[a_href (uri_of_string (fun () -> "test.com"))] arg ]

type tfull = (string -> Html_types.flow5 elt list)
type tphrasing = (string -> Html_types.phrasing elt list)

let a : tfull = ((f_link :> tphrasing) :> tfull)

let b : tfull = (f_link :> tfull)

您可以使用ocamlfind ocamlc -c -package eliom.server -thread test.ml编译此示例,并安装Eliom 6.

错误发生在最后一行,OCaml编译器抱怨f_link无法转换为tfull类型。

有人可以向我解释为什么不能直接强迫f_linktfull,但 可能会间接强制它tfull tphrasing作为中间步骤?

任何指向其背后的类型理论的指针也会受到欢迎。

1 个答案:

答案 0 :(得分:8)

一般强制算子,也称为双重强制,有一种形式

(<exp> : <subtype> :> <type>)

<subtype>类型可以有时省略,在这种情况下,它被称为单个强制。所以在你的情况下,正确的强制应该是这样的:

let a : tfull = (f_link : f_link_type :> tfull)

其中f_link_typef_link函数的一种类型。

the manual

中描述了失败的原因
  

前一个运算符有时无法强制表达expr   从类型typ1到类型typ2,即使类型typ1是类型的子类型   typ2:在当前的实现中,它只扩展了两个类型的类型   包含对象和/或多态变体的缩写,保留   只有在类类型(对象)中显式时才递归。如   上述算法的一个例外,如果两者都推断出expr的类型   和typ是基础的(即不包含类型变量),前者   运算符的行为与后者相同,采用推断类型expr   为typ1。如果前一个操作员失败,后一个操作员失败   应该使用。

让我试着用更简单的术语来表达。只有在知道域和域的情况下才能进行强制。但是,在许多情况下,您可以应用一种启发式方法,该方法将从codomain和当前表达式中推断出域。如果表达式的类型是基础的,没有递归和一些其他限制,则此启发式工作。基本上,如果域类型没有唯一最通用的类​​型,我们需要枚举所有可能的概括并检查每个可能的组合。