OCaml 函数生成器,Haskell 类型类和多重派生

17
众所周知,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,其参数为实现了ShowableReadable的模块。


2
这一定是我见过的写得最好的问题之一!希望有人能找到答案! - Lhooq
1个回答

15
当然,这其实很容易,使用模块包含即可。
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
其余部分是常规模块内容(完整说明请参见手册)

一些重度使用functor的库非常依赖这种结构子类型。例如,ocamlgraph中的每个functor都定义了自己的模块类型参数。以下是使用Kruskal module进行的示例。该functor期望一个类型为Kruskal.G的模块,该模块实现了Sig.G的子签名(大多数图形模块都实现了该签名)。


谢谢,这实际上相当容易!从某种意义上说,我们可以说 Haskell 的类型类系统和 OCaml 的模块和函子系统是等价的吗? - Samuele Giraudo
3
它们并不等价。如模块化类型类所述,ML的模块系统比Haskell的类型类更灵活和通用,但不允许递归。将它们结合起来意味着您不必手动编写函数应用,但也避免了Haskell每种类型只能导入一个类型类实例的问题。请参阅Stefan Wehr的ML模块和Haskell类型类:一种建设性比较第107-110页以获取差异摘要。 - sshine
3
更正:比我聪明的人指出,Oleg Kiselyov证明了这两者的等价性(在给定某些过时的Haskell类型类定义的情况下),尽管我找不到这篇文章,而现代Haskell类型类比ML模块更强大,因为它们提供了类型级函数。我将避免再作出任何大胆的陈述,继续编写酷炫的代码片段。;-) - sshine
2
《Haskell中的应用半透明函子(2004)》是Oleg Kiselyov和Chung-chieh Shan所著,您可以在以下链接中找到:https://mail.haskell.org/pipermail/haskell/2004-September/014515.html。 - sshine
Modular Type Classes 的原始链接已经失效。这里有两个备选位置:AB - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接