如何在OCaml或SML中表示来自Haskell的以下数据类型?
newtype Fix f = In (f (Fix f))
答案 0 :(得分:15)
我已经answered this question on the mailing-list了(我必须说我有点不高兴你在两个不同的地方提出这个问题而没有好几天的延迟,因为它可能引起重复的努力),但是让我#39; s在这里重现。
这里有一个难点,因为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"包装在 每个递归层。为此,您必须编译incumbing模块 (以及通过一个也看到这个equirecursion的所有模块 接口)与" -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
模块的语法很重,可能看起来很可怕。如果 你坚持认为你可以使用一流的模块来移动其中的一些用途 从仿函数到简单的函数。我选择以"简单"开头 首先要这样做。
高variables变种嫉妒可能是最严重的疾病 OCaml类型的崇拜者(或Haskellers,因为一些(好!)的原因 来到功能县的这些地方徘徊)。在实践中我们做到了 没有它没有太多的问题,但大量使用monad 变形金刚确实会通过这个仿函数步骤复杂化 这是它不是一个非常流行的风格的原因之一。 你也可以通过思考瑕疵来分散自己的注意力 支持它们的语言中的高级变量;该 对构造函数多态性的限制而不是任意的 类型级函数使它们的表达力低于你想要的。 我们计算出绝对完美的高阶细节 类型抽象,也许OCaml会跳转到它?
答案 1 :(得分:2)
我认为OCaml不允许你抽象类型构造函数。对于Fix的特定应用程序,我认为可以使用-rectypes
获得类似的效果。
$ ghci
GHCi, version 7.4.2: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> newtype Fix f = In (f (Fix f))
Prelude> type L = Fix []
Prelude> let w = In [] :: L
Prelude> let x = In [x] :: L
$ ocaml -rectypes
OCaml version 4.00.0
# type l = l list;;
type l = l list
# ([] : l);;
- : l = []
# let rec x = [x];;
val x : 'a list as 'a = [[[...]]]
# (x : l);;
- : l = [[[...]]]
我不是模块类型专家。可能有一种方法可以使用模块来比这更近。使用模块系统似乎一切皆有可能。