Ocaml中的开放式和封闭式联合类型 [英] Open and closed union types in Ocaml

查看:102
本文介绍了Ocaml中的开放式和封闭式联合类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我第一次研究OCaml,与F#和Haskell有一点背景.这样,看起来很熟悉,但没有一件事是开放"和封闭"联合(带有反引号和[<语法)的概念.

I'm looking into OCaml for the first time, having a bit of background with F# and Haskell. As such, a lot is familiar-looking, but one thing that isn't is the concept of "open" and "closed" unions (with the backtick and [< syntax).

这些有什么用?使用频率是多少?

What are these useful for and how often are they used?

推荐答案

gasche's answer has good advice. I'm going to explain open and closed unions a bit more.

首先,您需要区分两种联合:基本变体(无反引号)和多态变体(有反引号).

First, you need to distinguish the two kinds of unions: basic variants (no backtick) and polymorphic variants (with backtick).

  • 基本变体具有生成性:如果在不同的模块M1M2中用相同的构造函数名称定义两种类型,则您将具有不同的类型. M1.FooM2.Foo是不同的构造函数. `Foo始终是相同的构造函数,无论您在何处使用它.
  • 除此之外,多态变体可以完成基本变体可以完成的所有工作.但是,强大的功能会带来极大的复杂性,因此,只有在必要且谨慎使用时,才应使用它们.
  • Basic variants are generative: if you define two types with the same constructor names in different modules M1 and M2, you have different types. M1.Foo and M2.Foo are different constructors. `Foo is always the same constructor no matter where you use it.
  • Apart from this, polymorphic variants can do everything basic variants can do and more. But with great power comes great complexity, so you should use them only when necessary and carefully.

多态变量类型描述了该类型可能具有的构造函数.但是,许多多态变体类型并不是完全已知的-它们包含(行)类型变量.考虑一个空列表[]:其类型为'a list,它可以在许多为'a分配更具体类型的上下文中使用.例如:

A polymorphic variant type describes what constructors the type may have. But many polymorphic variant types are not fully known — they contain (row) type variables. Consider the empty list []: its type is 'a list, and it can be used in many contexts that assign more specific types to 'a. For example:

# let empty_list = [];;
val empty_list : 'a list = []
# let list_of_lists = [] :: empty_list;;
val list_of_lists : 'a list list = [[]]
# let list_of_integers = 3 :: empty_list;;
val list_of_integers : int list = [3]

行类型变量也是如此.开放式类型为[> … ],具有一个行变量,每次使用该值时,都可以实例化该行变量以覆盖更多构造函数.

The same holds for the row type variables. An open type, written [> … ], has a row variable that can be instantiated to cover more constructors each time the value is used.

# let foo = `Foo;;
val foo : [> `Foo ] = `Foo
# let bar = `Bar;;
val bar : [> `Bar ] = `Bar
# let foobar = [foo; bar];;
val foobar : [> `Bar | `Foo ] list = [`Foo; `Bar]

仅仅因为构造函数出现在一个类型中并不意味着该类型的每次使用都必须允许所有构造函数. [> …]表示类型必须至少具有这些构造函数,并且双重地[< …]表示一个类型最多必须具有这些构造函数.考虑一下此功能:

Just because a constructor appears in a type doesn't mean every use of that type has to allow all constructors. [> …] says that a type must have at least these constructors, and dually [< …] says that a type must have at most these constructors. Consider this function:

# let h = function `Foo -> `Bar | `Bar -> `Foo;;
val h : [< `Bar | `Foo ] -> [> `Bar | `Foo ] = <fun>

h仅能处理FooBar,因此输入类型可能不允许其他构造函数;但是可以在只允许Foo的类型上调用h.相反,h可能返回FooBar,并且使用h的任何上下文都必须允许FooBar(并且可以允许其他).

h is only capable of handling Foo and Bar, so the input type may not allow other constructors; but it's ok to call h on a type that only allows Foo. Conversely, h may return Foo or Bar, and any context where h is used must allow both Foo and Bar (and may allow others).

当对类型的最小和最大构造函数要求匹配时,就会出现封闭类型.例如,让我们添加h必须具有相同的输入和输出类型的约束:

Closed types arise when there are matching minimum and maximum constructor requirements on a type. For example, let's add the constraint that h must have the same input and output type:

# let hh : 'a -> 'a = function `Foo -> `Bar | `Bar -> `Foo;;
val hh : [ `Bar | `Foo ] -> [ `Bar | `Foo ] = <fun>

封闭类型很少会自然地从类型推断中产生.大多数时候,就像这里一样,它们是用户注释的结果.使用多态注释时,最好定义命名类型并至少在每个顶级函数上使用它们.否则,推断出的类型可能会比您想像的更普遍.尽管这很少会打开bug的大门,但这通常意味着任何类型错误的诊断时间都将比本来要晚,并且会生成很长的错误消息,使您很难找到有用的信息.

Closed types rarely arise naturally from type inference. Most of the time, like here, they are a consequence of a user annotation. When you use polymorphic annotations, it's a good idea to define named types and use them at least on every toplevel function. Otherwise the inferred type is likely to be a little more general than you thought. While this rarely opens the way to bugs, it often means that any type error will be diagnosed later than it could have been, and will generate a very long error message where it will be hard to find the helpful bits.

我建议阅读并进行操作(例如,在顶层重新键入示例,进行一些操作以确保您理解每个步骤)

I recommend reading and working through (i.e. retype the examples in the toplevel, play around a bit to make sure you understand each step) the polymorphic variant tutorial in the Ocaml manual.

这篇关于Ocaml中的开放式和封闭式联合类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆