OCaml中的FIx数据类型

Rom*_*ldo 3 recursion ocaml haskell sml fixpoint-combinators

如何在OCaml或SML中表示来自Haskell的以下数据类型?

newtype Fix f = In (f (Fix f))
Run Code Online (Sandbox Code Playgroud)

gas*_*che 16

我已经在邮件列表上回答了这个问题(我必须说我有点不高兴你在两个不同的地方提出这个问题而没有好几天的延迟,因为它可能引起的重复工作),但是让我们在这里重现它.

这里存在一个困难,因为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
Run Code Online (Sandbox Code Playgroud)

好消息是OCaml还支持等递归而不是等递归类型,它允许您在每个递归层删除"In"包装器.为此,您必须使用"-rectypes"选项编译incumbing模块(以及通过接口也看到此equirecursion的所有模块).然后你可以写:

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
Run Code Online (Sandbox Code Playgroud)

模块的语法很重,可能看起来很可怕.如果你坚持认为你可以使用一流的模块将其中一些用途从仿函数转移到简单的函数.我选择以"简单"的方式开始.

较高级别的变量嫉妒可能是OCaml型崇拜者(或Haskellers,因为某些(好的!)原因在功能县的这些部分徘徊)最严重的疾病.在实践中我们没有它没有太多的问题,但是大量使用monad变换器确实很复杂,这个functor步骤,这是它不是一个非常流行的风格的原因之一.你也可以通过考虑支持它们的语言中高等级变量的不完美来分散注意力; 构造函数多态性的限制而不是任意类型级函数使它们的表达力低于你想要的.在我们计算绝对完美的高阶类型抽象的细节的那一天,也许OCaml会跳到它?

  • 我只能感谢您的回答,并且很抱歉在两个不同的地方发布了该问题。当发布它时,我认为获得快速答复的机会很低,我希望获得最广泛的受众。对于由此可能造成的不便,我们深表歉意。今后我会对此更加谨慎。 (2认同)
  • 没有造成任何伤害!我有点脾气暴躁,让人们知道是件好事,这样他们就不会做得太过分,但作为回报,我必须感谢你提出了一个有趣的问题。 (2认同)
  • @Sarah 那是错误的,因为这两个问题之间没有任何联系,可以让一方面的人们注意到另一方给出的答案,并以此为基础,而不是重复工作。在两个不同的地方问同样的问题,而它们之间没有明确的联系,实际上反映了你认为人们回答所花费的时间不如你通过并行化可以节省的时间宝贵。我知道初学者没有考虑过,没关系。但是,如果你意识到这个问题并且仍然这样做,那就是以自我为中心、粗鲁和不尊重。 (2认同)

Jef*_*eld 3

我认为 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 = [[[...]]]
Run Code Online (Sandbox Code Playgroud)

我不是模块类型专家。可能有一种使用模块的方法可以比这更接近。使用模块系统似乎一切皆有可能。