双重胁迫什么时候有用?



我在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,但可以用tphrasing作为中间步骤间接胁迫它tfull

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

一般强制算子,又称双重胁迫,有形式

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

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

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

其中f_link_typef_link函数的一种类型。

手册中描述了它可能失败的原因:

前一个运算符有时无法强制表达式expr从类型typ1到类型typ2即使类型typ1是类型的子类型typ2:在当前的实现中,它只扩展了两个级别的类型 包含对象和/或多态变体的缩写,保留 仅当递归在类类型中显式时(对于对象)。如 上述算法的一个例外,如果推断的类型都exprtyp是地面的(即不包含类型变量),前者 运算符的行为与后者一样,采用推断的expr类型 作为typ1.如果前一个操作员发生故障,则后者 应该使用。

让我试着用更简单的术语来表达它。只有在域和共域都已知的情况下,强制才有可能。但是,在许多情况下,您可以应用启发式方法,该启发式方法将从协域和当前表达式类型推断域。如果表达式类型是 ground、没有递归和其他一些限制,则此启发式方法有效。基本上,如果域类型没有唯一的最通用类型,我们需要枚举所有可能的泛化并检查每个可能的组合。

相关内容

  • 没有找到相关文章

最新更新