OCaml函子、Haskell类型类和多重派生

j2cgzkjk  于 2022-11-14  发布在  其他
关注(0)|答案(1)|浏览(150)

众所周知,OCaml具有参数多态性,这导致了一些限制。Haskell通过它的类型类提供了一种 ad hoc 多态性,显然,这在某些情况下非常方便。同样众所周知的是,OCaml的模块和函子系统允许创建一种 ad hoc 多态性。例如,请参见Simon Shine here最近的伟大回答。
我的观点是,在Haskell中可以创建派生几个类型类的类型。例如:

data Person = Person { firstName :: String
                 , lastName :: String
                 , age :: Int
                 } deriving (Eq, Show, Read)

这对于定义具有多个特性的类型非常方便(在给定的示例中,允许类型Person的值支持相等性测试、可打印和可读)。
我的问题如下:我们能在OCaml中简单地做同样的事情吗?我所说的 simply 是指使用语言的基本语法,而不需要很多技巧。
为了给予一个比较具体的例子,假设我们有两个OCaml签名

module type Showable = sig
    type t
    val to_string : t -> string
end

module type Readable = sig
    type t
    val from_string : string -> t
end

目标是写一个函子F,它由一个实现ShowableReadable的模块参数化。

gfttwv5a

gfttwv5a1#

当然,这实际上很简单,使用模块包含。

module type S = sig
  include Showable
  include Readable with type t := t (* destructive substitution *)
end
    
module F ( M : S ) = struct
  let fake_id x = M.from_string @@ M.to_string x
end

手册中对破坏性替代进行了说明:http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec234
剩下的是常规的模块内容(完整的解释请参见手册)
一些函子很重的库非常依赖于这种结构化的子类型。例如,ocamlgraph中的每个函子都定义了自己的模块类型参数。这里是Kruskal module的一个例子。函子期望一个Kruskal.G类型的模块,它实现了Sig.G的子签名(大多数图模块都实现了)。

相关问题