Language agnostic 编码与将存在类型编码为通用类型时使用存在类型
在我们将存在类型转换为一个通用类型之后,我试图更好地理解编码与使用存在类型之间的细微差别。简而言之,在我看来,使用存在主义类型比编码存在主义类型容易得多,下面我将解释这对我意味着什么。为了更好地解释这一点,让我们从逻辑的两条规则开始Language agnostic 编码与将存在类型编码为通用类型时使用存在类型,language-agnostic,ocaml,type-systems,existential-type,quantifiers,Language Agnostic,Ocaml,Type Systems,Existential Type,Quantifiers,在我们将存在类型转换为一个通用类型之后,我试图更好地理解编码与使用存在类型之间的细微差别。简而言之,在我看来,使用存在主义类型比编码存在主义类型容易得多,下面我将解释这对我意味着什么。为了更好地解释这一点,让我们从逻辑的两条规则开始 ∀x、 P(x)⇒ ¬(∃x、 P(x)) ∃x、 P(x)⇒ ¬(∀x、 P(x)) 从这个,我们有那个 val int_package : (int mypackage -> '_a) -> '_a = <fun> val str_pac
val int_package : (int mypackage -> '_a) -> '_a = <fun>
val str_package : (string mypackage -> '_a) -> '_a = <fun>
type 't mypackage = {
add : 't * 't -> 't;
fromInt : int -> 't;
toString : 't -> string};;
let int_package = {
add = (fun (x,y) -> x+y) ;
fromInt = (fun x->x) ;
toString = (fun x->string_of_int x)};;
let str_package = {
add = (fun (x,y) -> x^y) ;
fromInt = (fun x->string_of_int x) ;
toString = (fun x-> x)};;
let simpleProg fns =
let exp01 = fns.fromInt 1 in
let exp02 = fns.fromInt 2 in
let exp03 = fns.add (exp01,exp02) in
fns.toString exp03
let _ = simpleProg int_package;;
let _ = simpleProg str_package;;
这使用了上面的存在规则。就类型而言,我们有
val int_package : int mypackage
val str_package : string mypackage
val simpleProg : 'a mypackage -> string = <fun>
这里,我们有
val int_package : (int mypackage -> '_a) -> '_a = <fun>
val str_package : (string mypackage -> '_a) -> '_a = <fun>
我想我在这个过程中学到的最大的一点就是,这种重新编码的技巧颠倒了事物的构造顺序。本质上,这些包建立了一个过程,在这个过程中,它们接受一个程序,然后将这个程序应用于它们的内部表示。通过使用此技巧,包的内部类型被隐藏。虽然这在理论上等同于存在主义类型,但就我个人而言,我发现这个过程不同于皮尔斯的《类型和编程语言》一书中所描述的存在主义类型的直接实现
直接回答我上面的问题
此外,通用软件包是一个可怕的词。int_包和str_包是专用的,所以它们不是真正通用的。大多数情况下,我没有更好的名字。坦率地说,这有点让我不知所措,但我想我知道你的基本想法。我记得,Haskell中也有类似的东西支持存在类型 但是,第二个构造的类型在我看来并不是很有用:
val int_package : (int mypackage -> '_a) -> '_a = <fun>
val int\u package:(int mypackage->'\u a)->'\u a=
这是一种单态类型,其中\u a
尚未指定。它不是多态类型。这意味着您只能给它一种类型的程序。如果您编写的第二个程序希望返回int而不是字符串,那么您的存在性包将不允许您调用它。至少在我看来是这样的
第一个构造有一个真正的多态类型,因此它看起来应该工作得更好
(一个知识更渊博的类型理论类型的人可能会提供更多的帮助:-)我真的不理解你的问题,但你对存在主义的编码似乎不正确 正如你所提到的,如果你想模仿
∃'t、 "t mypackage
,则必须创建一个类型
∀'y. (∀'t. 't mypackage -> 'y) -> 'y
但这不是OCaml类型('t mypackage->'y)->'y
,更准确地说
∀'y. ∀'t. ('t mypackage -> 'y) -> 'y
看量词的位置
OCaml的类型方案是最量化的,它不能有像∀'Y(∀'t、 't mypackage->'y)->'y
,但我们可以用其记录多态字段来模拟它:
type 'y packed = { unpacked : 't. 't mypackage -> 'y }
(* mimicing ∀'t. 't mypackage -> 'y *)
使用此类型,存在类型可以实现为
type 'y closed_package = 'y packed -> 'y
(* mimicing a higher ranked type ∀'y. (∀'t. 't mypackage -> 'y) -> 'y,
which is equivalent with ∃'t. 't mypackage *)
如果您不喜欢暴露类型变量'y
,可以使用记录多态字段再次隐藏它:
type really_closed_package = { l : 'y. 'y closed_package }
包实现可以打包到此接口中,如下所示:
let closed_int_package = { l = fun packed -> packed.unpacked int_package }
let closed_str_package = { l = fun packed -> packed.unpacked str_package }
由于这些打包版本具有相同的类型,我们可以将它们放入列表中:
let closed_packages = [ closed_int_package; closed_str_package ]
这通常是我们想要对存在主义做的
现在编码完成了。使用它也需要一些复杂性,但非常简单:
let doubled_int_string p x =
let x = p.fromInt x in
p.toString (p.add (x,x))
double\u int\u string
用于打开的包,我们不能简单地将其用于关闭的包。我们需要一些转换:
let () =
(* Using "universal" packages *)
print_endline (double_int_string int_package 3);
print_endline (double_int_string str_package 3);
(* Equivalents using "existential" packages *)
print_endline (closed_int_package.l { unpacked = doubled_int_string } 3);
print_endline (closed_str_package.l { unpacked = doubled_int_string } 3)
正如camlspotter所指出的,您的编码不太正确,应该使用以下类型:
type 'k mypackage_cont = { p: 't. 't mypackage -> 'k }
那么您的编码包将具有以下类型:
val int_package1 : 'k mypackage_cont -> 'k
val str_package1 : 'k mypackage_cont -> 'k
而你的另一个版本
let () =
(* Using "universal" packages *)
print_endline (double_int_string int_package 3);
print_endline (double_int_string str_package 3);
(* Equivalents using "existential" packages *)
print_endline (closed_int_package.l { unpacked = doubled_int_string } 3);
print_endline (closed_str_package.l { unpacked = doubled_int_string } 3)
type 'k mypackage_cont = { p: 't. 't mypackage -> 'k }
val int_package1 : 'k mypackage_cont -> 'k
val str_package1 : 'k mypackage_cont -> 'k
val int_package2 : int mypackage
val str_package2 : string mypackage
# [ int_package1; str_package1; ];;
- : ('a mypackage_cont -> 'a) list = [<fun>; <fun>]
# [ int_package2; str_package2 ];;
Characters 16-28:
[ int_package2; str_package2 ];;
^^^^^^^^^^^^
Error: This expression has type string mypackage
but an expression was expected of type int mypackage
Type string is not compatible with type int