我偶然发现了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_link
加tfull
,但 可能会间接强制它tfull
tphrasing
作为中间步骤?
任何指向其背后的类型理论的指针也会受到欢迎。
答案 0 :(得分:8)
一般强制算子,也称为双重强制,有一种形式
(<exp> : <subtype> :> <type>)
<subtype>
类型可以有时省略,在这种情况下,它被称为单个强制。所以在你的情况下,正确的强制应该是这样的:
let a : tfull = (f_link : f_link_type :> tfull)
其中f_link_type
是f_link
函数的一种类型。
前一个运算符有时无法强制表达
expr
从类型typ1
到类型typ2
,即使类型typ1
是类型的子类型typ2
:在当前的实现中,它只扩展了两个类型的类型 包含对象和/或多态变体的缩写,保留 只有在类类型(对象)中显式时才递归。如 上述算法的一个例外,如果两者都推断出expr
的类型 和typ
是基础的(即不包含类型变量),前者 运算符的行为与后者相同,采用推断类型expr
为typ1
。如果前一个操作员失败,后一个操作员失败 应该使用。
让我试着用更简单的术语来表达。只有在知道域和域的情况下才能进行强制。但是,在许多情况下,您可以应用一种启发式方法,该方法将从codomain和当前表达式中推断出域。如果表达式的类型是基础的,没有递归和一些其他限制,则此启发式工作。基本上,如果域类型没有唯一最通用的类型,我们需要枚举所有可能的概括并检查每个可能的组合。