重用和扩展 Ocaml 中定义的类型
在 Ocaml 中,是否有一个简单的构造/样式来扩展定义的类型?
假设我们有布尔类型,
bool2 = True | False
现在我们想将其扩展为三值逻辑。在 Ocaml 中,有没有比像这样重新定义 bool2 更优雅的:
bool3 = True | False | ThirdOne
In Ocaml, is there a simple construct/style to extend a defined type?
Say, if we have the boolean type
bool2 = True | False
Now we want to extend it for 3-valued logic. In Ocaml, is there more elegant one than redefining bool2 like this:
bool3 = True | False | ThirdOne
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
多态变体提供了这个功能:
就是这样。
多态变体还有另一个有用的快捷方式。在模式匹配中,使用以
#
开头的类型名称:应谨慎使用多态变体,因为它们很容易导致混乱的错误消息。如果原始类型
bool2
无论如何都不是多态变体,则两种类型的并集将按如下方式实现。假设bool2是核心类型bool,我们使用经典变体的定义是:在模式匹配中,编译器将检查是否覆盖了所有情况,而不需要类型注释。它看起来像这样:
Polymorphic variants provide this functionality:
That's it.
There is another useful shortcut for polymorphic variants. In pattern-matching, use the type name preceded by
#
:Polymorphic variants should be used with caution as they can easily lead to confusing error messages. If the original type
bool2
is not a polymorphic variant anyway, the union of two types is achieved as follows. Let's assumebool2
is the core typebool
, our definition using classic variants is:In pattern-matching, the compiler will check that all cases are covered, without requiring type annotations. It looks like this:
我建议不要过度使用多态变体。它们在纸面上看起来不错,但更灵活的推理和子类型随时都会给你带来麻烦。当我使用多态变体时,我尝试确保每次使用都用精确的约束类型表达式进行注释。
我建议返回并修改您的旧代码,因为这似乎很自然。如果您在编写代码时考虑到了可扩展性,特别是避免了
bool2
类型上的_
模式,那么编译器会警告您任何地方假设仅创建了两个构造函数。编译器对类型修改的反馈非常有用,因为它是使程序正确的机械帮助。这种做事方式当然有一些缺点。其中之一是修改类型定义,然后修改每个用例可能无法很好地适应您通常的编译测试实践:如果您在大型代码库上执行此操作,则在项目编译之前您将需要做大量的事情再次干净(因此可以进行测试)。您可以将修改拆分为版本控制系统的多个补丁,但这意味着某些中间提交状态不会编译,这不太令人愉快。另一种可能性是更改这些位置仅添加运行时故障(
| Third_one -> assert false
),然后您就有可编译的代码,并且可以在运行时纠正这些故障 -应用程序测试期间的时间。但我仍然认为静态编译器反馈对于代码维护来说是一个很好的帮助。还可以选择将代数数据类型包装在“扩展代数数据类型”中
type bool3 = New |旧的 bool2
,在您作为马丁答案的评论给出的链接中进行了讨论。这可能是在不破坏编译的情况下从一种数据类型转换到另一种数据类型的好方法,但从长远来看,这是痛苦的,特别是当您将更多的扩展堆叠在一起时。当然,在某些情况下真正需要的是一种通过添加代码而不是修改代码来扩展数据类型的方法,这种方法既静态安全,又易于编译、运行和测试,并且运行高效。时间。这是表达式问题的一个实例,它们是各种解决方案,多态变体是其中之一他们。但在常见情况下,您不需要仅添加代码的额外灵活性,并且不值得相关语言功能的额外复杂性,因此我建议坚持使用普通的旧变体类型,除非它明显是一个巨大的获得做不同的事情。
PS:关于多态性变体及其与表达问题的关系,强制性论文是 通过多态变体进行代码重用,作者:Jacques Garrigue。
I would advise against the immoderate use of polymorphic variants. They look nice on paper, but the more flexible inference and subtyping will come to bite you back at any time. When I use polymorphic variants, I try to make sure that every use is annotated with a precise constraining type expression.
I would suggest going back and modifying your old code, as it seems natural to do. If you have written your code with extensibility in mind, and in particular avoided
_
-patterns on thebool2
type, then the compiler will warn you of any place where the assumption that there are only two constructors is made. This compiler feedback on type modification is very useful, as it is a mechanical help to make your program correct.This way of doing things has of course some drawbacks. One of them is that modifying the type definition, then modifying each use case may not work well with your usual compile-test practice: if you do that on a large code base, you will have important amount of things to do before your project compiles cleanly again (and thus can be tested). You may split your modification in several patches to your version control system, but that means some intermediary committed states do no compile, which is not very pleasing. The other possibility is to change those place only to add a run-time failure (
| Third_one -> assert false
), then you have compilable code and you can correct those failures as they happen at run-time during the testing of the application. But I still think the static compiler feedback is a good help for code maintenance.There is also the option of wrapping the algebraic datatype in an "extended algebraic datatype"
type bool3 = New | Old of bool2
, which is discussed in the link you give as a comment of Martin answer. This may be a good way to transition from one datatype to the other without breaking compilation, but on the long term it is painful, especially if you stack more of those extensions on top of each other.Of course, what would be really needed in some situations would be a way to extend the datatype by code addition, instead of code modification, in a way that is both statically safe, easier to compile, run and test, and efficient at run-time. This is an instance of the Expression Problem, of which they are various solutions, polymorphic variants being one of them. But in the common case, you don't need the additional flexibility of doing code addition only, and it's not worth the additional complexity of the concerned language features, so I would advise to stick with plain old variant types unless it is demonstrably a huge gain to do differently.
PS: regarding polymorphic variants, and their relation to the expression problem, the obligatory paper is Code reuse through polymorphic variants by Jacques Garrigue.
根据手头的任务,您还可以找到可扩展变体类型有用。更多信息和使用案例请参见此处。
Depending on the task at hand, you may also find Extensible Variant Types useful. More information and use cases here.