ocaml - 动态创建两种记录类型之一的函数

标签 ocaml

我尝试在 Ocaml 中实现这种 OO 情况: 两类X1X2 , 两个子类型 X ( X1 <: XX2 <: X ),我想编写一个动态返回 X 的函数要么是 X1X2 .

但是我听说在 Ocaml 中避免使用类并使用模块通常会很好,所以我试图像这样表示我的问题(过于简化但仍然很重要): 两个模块X1X2 ,并且我希望我的函数能够动态决定是否返回 X1.tX2.t .

module type X = sig
  type choice
  type t
  (* some methods we don't care about in this instance, like
     val modifySomething : t -> t *)
end

module Xbase = struct
  type choice = Smth | SmthElse
end

module X1 = (
struct
  include Xbase
  type t = { foo : int; bar : int }
end : X)

module X2 = (
struct
  include Xbase
  type t = { foo : int; star : int }
end : X)

module XStatic =
struct
  (* construct either an X1.t or X2.t from the string *)
  let read : string -> 'a =
    function
    | "X1" -> { X1.foo = 0, bar = 0 }
    | "X2" -> { X2.foo = 1, star = 1 }
end

但这失败了 Error: Unbound record field label X1.fooread功能。 我尝试了不同的排列方式,例如使用 let open X1 in { foo = 0, ... }但无济于事。

我解决这个问题的方法是根本错误的(即我应该使用类,因为这对模块来说是不可能/不切实际的)还是我只是错过了一些微不足道的东西?

编辑:澄清我要解决的问题并重命名module Xmodule XBase将其与 module type X 区分开来.

最佳答案

最简单的方法是使用 sum 类型(免责声明:我没有尝试编译代码):

module X1 = struct
  type t = { foo : int; bar : string }
  let modify_foo = ...
end
module X2 = struct
  type t = { foo : int; star : bool }
  let modify_foo = ...
end
type x1_or_x2 =
  | Left of X1.t
  | Right of X2.t

let read = function
  | "X1" -> Left { X1.foo = 1; bar = "bar" }
  | "X2" -> Right { X2.foo = 1; star = true }

let modify_foo = function
  | Left x1 -> Left (X1.modify_foo x1)
  | Right x2 -> Right (X2.modify_foo x2)

如果您想利用 X1.tX2.t 共享一些共同结构这一事实,您可以分解类型。这个想法是它们与产品类型同构,分别是 common_part * specific_to_x1common_part * specific_to_x2x1_or_x2 类型因此是 (common * specific_to_x1) + (common * specific_to_x2),相当于 common * (specific_to_x1 + specific_to_x2)

type common = { foo : int }
let modify_foo_common : common -> common = ...

type specific_x1 = { bar : string }
type specific_x2 = { star : bool }

type x1_or_x2 = common * specific_x1_or_x2
and specific_x1_or_x2 =
  | Left of X1.t
  | Right of X2.t

let read = function
  | "X1" -> { foo = 1 }, Left { bar = "bar" }
  | "X2" -> { foo = 1 }, Right { star = true }

let modify_foo (common, specific) = (modify_foo_common common, specific)

这样,作用于公共(public)部分的定义不会重复,而是可以声明一次。

PS:另请参阅这个非常相关的问题,您可能对此感兴趣并且有一个很好的答案(镜头!):Ptival: Statically “extend” a record-ish data type without indirection hassle

关于ocaml - 动态创建两种记录类型之一的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13798358/

相关文章:

ssl - Ocaml如何获取https url

ocaml - 在 OCaml 中定义多元函数的正确方法是什么?

functional-programming - 如何将函数应用于变体?

function - 是否有一个函数的名称,该函数接受一段数据和一个函数列表,并将每个函数应用于最后一个函数的结果?

ocaml - OCaml 中的高阶类型(幻像类型子类型化)

C 到 OCaml - for 循环内的 If 条件 OCaml

list - 匹配元组列表中的一项

OCaml 中的空白问题

haskell - Objective-C 的跨平台函数式语言

functional-programming - "square"元组的 Ocaml 模式匹配?