Ocaml (可选)将额外数据附加到类型

Ocaml (可选)将额外数据附加到类型,ocaml,Ocaml,假设我有一个带有一系列递归类型声明的模块,并且已经有大量的使用者执行打开M,然后使用类型1、类型2和类型3 module M = struct type type1 = | T1_Case1 of string * type2 | T1_Case2 of type3 and type2 = type3 list and type3 = | T3_Case1 of type1 | T3_Case2 of int end 在其中一个处理步骤中,需要将

假设我有一个带有一系列递归类型声明的模块,并且已经有大量的使用者执行
打开M
,然后使用
类型1
类型2
类型3

module M = struct
  type type1 = 
    | T1_Case1 of string * type2
    | T1_Case2 of type3
  and type2 = type3 list
  and type3 = 
    | T3_Case1 of type1
    | T3_Case2 of int
end
在其中一个处理步骤中,需要将这些类型中的一个或多个扩展为添加了一些额外数据的类型,类似于:

  type type1 = 
    | T1_Case1 of string * type2
    | T1_Case2 of type3
  and type2 = type3 list
  and type3_ = 
    | T3_Case1 of type1
    | T3_Case2 of int
  and type3 = extra_data * type3_
是否有可能在不涉及外部codegen工具或破坏现有代码的情况下实现这一点

后一个选项排除了将
M
转换为注释类型参数化的函子的可能性:

(* won't work since all places that used to deal with type3 should be updated *)
module type AnnotationT = sig type t end

module M_F(Annotation: AnnotationT) = struct
  type type1 = 
    | T1_Case1 of string * type2
    | T1_Case2 of type3
  and type2 = type3 list
  and type3_ = 
    | T3_Case1 of type1
    | T3_Case2 of int
  and type3 = Annotation.t * type3_
end

module M = struct 
 include M_F(struct type t = unit end)
end
我想我需要这样的东西(因为我不能在类型声明中使用函子应用程序,所以不起作用):


如果从functor切换到参数化类型,则可以尝试工作,如下所示:

module type AnnotatorType = sig

  type 'a annotated

end

module Annotated_M(Annotator: AnnotatorType) = struct

  type type1 = 
    | T1_Case1 of string * type2
    | T1_Case2 of type3
  and type2 = type3 list
  and type3_ = 
    | T3_Case1 of type1
    | T3_Case2 of int
  and type3 = type3_ Annotator.annotated

end

module M = struct
  include Annotated_M(struct
    type 'a annotated = 'a
  end)
end

module M2 = struct
  include Annotated_M(struct
    type 'a annotated = extra_data * 'a
  end)
end

这听起来像是问题的一个例子,尽管问题
Y
有技术上的解决办法,但问题
X
仍然会存在。稍后让我详细介绍一下,但现在我要提出几个技术解决方案

  • 可以使用定义类型的每个分支(或某些分支)的类型参数化定义类型的函子,例如

    module type Variants = sig 
      type t1
      type t2
      ...
    end
    
    module Define(V : Variants) = struct
      type t = V of t1 | V of t2 ...
    end
    
  • 您可以改为使用参数化类型:

    type ('a,'b,..) t = A of 'a | B of 'b
    
  • 这两种解决方案都有点滥用数据构造函数,因为它们以效率换取灵活性

    现在让我对
    X
    问题做一点详细说明。我的猜测是,您试图表示语言的一些转换(即,一些中间表示、DSL等)。你有一对表示,它们彼此非常同构,但是它们定义了不同的类型,你感觉到的问题是这两种类型的定义中涉及的代码重复。代码重复是遗漏抽象的常见指标。OCaml中的类型定义不引入抽象,而是定义类型的表示。抽象是由模块类型引入的,并由使用特定类型表示的模块实现。因此,您真正需要解决
    X
    问题的是一个适当的抽象。在我们的例子中,依赖标记嵌入迫使我们披露我们的表示,并使其具体化而不是抽象化。这有时很方便,但相当脆弱,很快就会导致代码重复。一个可能的解决方案是,它允许我们定义可扩展的抽象,而不必拘泥于特定的表示

    type ('a,'b,..) t = A of 'a | B of 'b