【问题标题】:Extending an existing type in OCaml在 OCaml 中扩展现有类型
【发布时间】:2010-12-17 07:59:57
【问题描述】:

我最近一直在做一些 OCaml 编程来学习该语言并更加熟悉函数式编程。最近,我开始认为我希望能够扩展现有类型(内置类型或我自己的类型),例如:

type bexp =
  And of bexp * bexp
| Or of bexp * bexp
| Xor of bexp * bexp
| Not of bexp;;

现在假设我想为这种类型添加一个 Nop 变体,但仅用于新类型 - 有点像继承。嘿,这些应该是代数数据类型,对吧?那么为什么不这样:

type nbexp = bexp | Nop nbexp ;;

...但这不是有效的 OCaml,它会给出语法错误。基本上,我想做的是说我希望 nbexp 包含 bexp 包含的所有内容,并在其中添加一个 Nop。我想这是不可能的,因为例如,如果您使用 And 构造函数,则无法确定它是 bexp 类型还是 nbexp 类型。 (我认为构造函数 Nop 采用 nbexp 也可能有问题。)

那么有没有办法在 OCaml 中做这样的事情?而且,这在 Haskell 中是可行的吗(也许是类型类)?

【问题讨论】:

标签: haskell types functional-programming ocaml type-systems


【解决方案1】:

更新:Ocaml 现在具有可扩展类型。 http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec246

你会这样做

type bexpr += Nop of bexpr

【讨论】:

    【解决方案2】:

    一个有趣的解决方案是使用多态变体:

    type bexp =
    [ `And of bexp * bexp
    | `Or of bexp * bexp
    | `Xor of bexp * bexp
    | `Not of bexp ];;
    
    type nbexp = [ bexp | `Nop of nbexp ];;
    

    请注意,多态变体比普通变体更棘手,但允许类型扩展。

    一个有趣的表达式评估示例,带有扩展,使用多态变体,可以在 ocaml 源的测试目录中找到,请参阅svn

    【讨论】:

    • 我听说过这些,但还没有真正使用它们。这给了我一个很好的实际理由来了解更多关于它们的信息。谢谢。
    【解决方案3】:

    嘿,这些应该是代数数据类型吧?

    没错。而algebraic data types 是由标记的(又名区分的)联合和产品构成的。您想要的只是一个(未标记的)联合,它 不是 一种代数数据类型,并且不受 Haskell 支持。 OCaml 具有多态变体(请参阅其他答案)。

    Typed Scheme 确实支持非标记联合,因此您可能需要检查一下。

    【讨论】:

      【解决方案4】:

      正如您自己正确推测的那样,这在代数类型中是不可能的。我同意 Apocalisp 的建议,您可以简单地将 nbexp 的“继承”部分包装在自己的构造函数中。

      我要补充一点,代数类型缺乏继承是它们美妙之处的一部分。这意味着像And(foo, bar) 这样的表达式是不明确的类型,并且强制转换(向上或向下)在类型系统中没有任何作用。这会产生更高的安全性和更高的清晰度。当然,程序员确实需要明确处理他/她想要与nbexp 的bexp 部分进行交互的情况,但是如果您考虑一下,这就是提高安全性和清晰度的方式在实践中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多