我已经在邮件列表上回答了这个问题 https://sympa.inria.fr/sympa/arc/caml-list/2012-10/msg00109.html(我必须说,我有点不高兴你在两个不同的地方提出这个问题,没有延迟几天,因为它可能会引起重复的工作),但让我们在这里重现它。
这里有一个困难,因为 OCaml 不支持更高排名
类型变量。在这份声明中,f
不是“类型”,而是“类型”
运算符”(种类* -> *
)。要在 OCaml 中执行相同的操作,您可以使用
函子(不是 Haskell 函子;在 OCaml 中,“函子”一词表示
可能依赖于其他模块/函子的高阶模块);
函子是更高级的。
module type ParamType = sig
type ('a, 'b) t
end
module Fix (M : ParamType) = struct
type 'b fix = In of ('b fix, 'b) M.t
end
module List = struct
module Param = struct
type ('a, 'b) t = Nil | Cons of 'b * 'a
end
include Fix(Param)
end
open List.Param
open List
let rec to_usual_list =
function
| In Nil -> []
| In (Cons (x, xs)) -> x :: to_usual_list xs
好消息是 OCaml 还支持等递归而不是
iso-recursive 类型,它允许您删除位于以下位置的“In”包装器
每个递归层。为此,您必须编译嵌入模块
(以及所有也通过
接口)与“-rectypes”选项。然后你可以写:
module type ParamType = sig
type ('a, 'b) t
end
module EqFix (M : ParamType) = struct
type 'b fix = ('b fix, 'b) M.t
end
module EqList = struct
module Param = struct
type ('a, 'b) t = Nil | Cons of 'b * 'a
end
include EqFix(Param)
end
open EqList.Param
let rec to_usual_list =
function
| Nil -> []
| (Cons (x, xs)) -> x :: to_usual_list xs
模块的语法相当繁重,可能看起来很可怕。如果
您坚持可以使用一流的模块来移动其中一些用途
从函子到简单函数。我选择从“简单”开始
首先的方法。
高等变量嫉妒可能是最严重的疾病
OCaml 类型的崇拜者(或出于某些(好的!)原因的 Haskellers)
来功能县的这些地方闲逛)。在实践中我们这样做
没有它不会有太多问题,但大量使用 monad
变压器确实会因为这个函子步骤而变得复杂,
这是它在这里不是很流行的原因之一。
你也可能会因为思考自己的不完美之处而分散自己的注意力。
支持它们的语言中的高级变量;这
对构造函数多态性的限制而不是任意的
类型级函数使它们的表达能力低于您的预期。
我们研究出绝对完美的高阶细节的那一天
类型抽象,也许 OCaml 会跳转到它?