双重强制何时有用?
When is double coercion useful?
我在 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)
您可以使用安装了 Eliom 6 的 ocamlfind ocamlc -c -package eliom.server -thread test.ml
编译此示例。
错误发生在最后一行,OCaml 编译器抱怨 f_link
无法转换为类型 tfull
。
谁能给我解释一下为什么不能直接将 f_link
强制转换为 tfull
,但是可以 将其强制转换为 tfull
间接使用 tphrasing
作为中间步骤?
也欢迎任何指向它背后的类型理论的指针。
通用强制转换运算符,也称为双重强制转换,具有以下形式
(<exp> : <subtype> :> <type>)
<subtype>
类型可以有时省略,在这种情况下它被称为单一强制转换。所以在你的情况下,正确的强制转换应该是这样的:
let a : tfull = (f_link : f_link_type :> tfull)
其中 f_link_type
是 f_link
函数的一种类型。
可能失败的原因详见the manual:
The former operator will sometimes fail to coerce an expression expr
from a type typ1
to a type typ2
even if type typ1
is a subtype of type
typ2
: in the current implementation it only expands two levels of type
abbreviations containing objects and/or polymorphic variants, keeping
only recursion when it is explicit in the class type (for objects). As
an exception to the above algorithm, if both the inferred type of expr
and typ
are ground (i.e. do not contain type variables), the former
operator behaves as the latter one, taking the inferred type of expr
as typ1
. In case of failure with the former operator, the latter one
should be used.
让我试着用更简单的术语来表达。仅当域和辅域都已知时才可能进行强制转换。但是,在许多情况下,您可以应用一种启发式方法,从共同域和当前表达式类型推断域。如果表达式类型是基础的、没有递归和一些其他限制,则此启发式方法有效。基本上,如果域类型没有唯一的最一般类型,我们需要枚举所有可能的概括并检查每个可能的组合。
我在 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)
您可以使用安装了 Eliom 6 的 ocamlfind ocamlc -c -package eliom.server -thread test.ml
编译此示例。
错误发生在最后一行,OCaml 编译器抱怨 f_link
无法转换为类型 tfull
。
谁能给我解释一下为什么不能直接将 f_link
强制转换为 tfull
,但是可以 将其强制转换为 tfull
间接使用 tphrasing
作为中间步骤?
也欢迎任何指向它背后的类型理论的指针。
通用强制转换运算符,也称为双重强制转换,具有以下形式
(<exp> : <subtype> :> <type>)
<subtype>
类型可以有时省略,在这种情况下它被称为单一强制转换。所以在你的情况下,正确的强制转换应该是这样的:
let a : tfull = (f_link : f_link_type :> tfull)
其中 f_link_type
是 f_link
函数的一种类型。
可能失败的原因详见the manual:
The former operator will sometimes fail to coerce an expression
expr
from a typetyp1
to a typetyp2
even if typetyp1
is a subtype of typetyp2
: in the current implementation it only expands two levels of type abbreviations containing objects and/or polymorphic variants, keeping only recursion when it is explicit in the class type (for objects). As an exception to the above algorithm, if both the inferred type ofexpr
andtyp
are ground (i.e. do not contain type variables), the former operator behaves as the latter one, taking the inferred type ofexpr
astyp1
. In case of failure with the former operator, the latter one should be used.
让我试着用更简单的术语来表达。仅当域和辅域都已知时才可能进行强制转换。但是,在许多情况下,您可以应用一种启发式方法,从共同域和当前表达式类型推断域。如果表达式类型是基础的、没有递归和一些其他限制,则此启发式方法有效。基本上,如果域类型没有唯一的最一般类型,我们需要枚举所有可能的概括并检查每个可能的组合。