众所周知,OCaml具有参数多态性,这导致了一些限制。Haskell通过其类型类提供了特设多态性,这在某些情况下显然非常方便。众所周知,OCaml的模块和函数系统允许创建一种特设多态性。例如,请参阅Simon Shine最近的精彩回答。
我的观点是,在Haskell中可以创建派生多个类型类的类型。例如:
data Person = Person { firstName :: String
, lastName :: String
, age :: Int
} deriving (Eq, Show, Read)
这对于定义具有几个特性的类型非常方便(允许Person
类型的值支持相等测试,在给定的示例中是可打印的和可读的)。
我的问题是:我们能简单地在OCaml中做同样的事情吗?我所说的只是,意思是使用语言的基本语法,没有很多技巧。
举一个具体的例子,假设我们有两个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
,该函子由实现Showable
和Readable
的模块参数化。
当然,这其实很容易,使用模块包含。
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模块的一个示例。函子期望有一个类型为Kruskal.G
的模块,它实现了Sig.G
的子签名(这是由大多数图模块实现的)。