【问题标题】:Higher-order type constructors and functors in OcamlOcaml 中的高阶类型构造函数和函子
【发布时间】:2010-12-31 11:28:35
【问题描述】:

可以以下多态函数

let id x = x;;
let compose f g x = f (g x);;
let rec fix f = f (fix f);;     (*laziness aside*)

为类型/类型构造函数或模块/函子编写?我试过了

type 'x id = Id of 'x;;
type 'f 'g 'x compose = Compose of ('f ('g 'x));;
type 'f fix = Fix of ('f (Fix 'f));;

对于类型,但它不起作用。

这是用于类型的 Haskell 版本:

data Id x = Id x
data Compose f g x = Compose (f (g x))
data Fix f = Fix (f (Fix f))

-- examples:
l = Compose [Just 'a'] :: Compose [] Maybe Char

type Natural = Fix Maybe   -- natural numbers are fixpoint of Maybe
n = Fix (Just (Fix (Just (Fix Nothing)))) :: Natural   -- n is 2

-- up to isomorphism composition of identity and f is f:
iso :: Compose Id f x -> f x
iso (Compose (Id a)) = a

【问题讨论】:

  • 我不是 100% 确定,因为我不了解 Haskell,而且我不清楚 Compose fgx =... 在 Haskell 中的实际含义,但您可能有兴趣知道OCAML 的开发版本具有一流的模块。
  • 我很确定你不能在 ML 中做到这一点,因为你需要更高种类的多态性。你能举一些例子来说明你将如何在 Haskell 中使用这些类型吗?
  • nlucaroni,很有趣! (链接是caml.inria.fr/cgi-bin/viewcvs.cgi/ocaml/branches/fstclassmod 我相信)Chris Conway,我添加了一些示例。

标签: functional-programming ocaml


【解决方案1】:

Haskell 允许更高种类的类型变量。 ML 方言,包括 Caml,只允许类型变量“*”。翻译成简单的英文,

  • 在 Haskell 中,类型变量 g 可以对应于“类型构造函数”,例如 MaybeIO 或列表。因此,如果 gMaybe 并且 xInteger,则您的 Haskell 示例中的 g x 可以(行话:“善意”)。

  • 1234563因此,永远尝试将类型变量应用于另一种类型是正确的。

据我所知,ML 中的这种限制没有深层原因。最可能的解释是历史偶然性。当 Milner 最初提出他关于多态性的想法时,他使用了非常简单的类型变量,只代表种类 * 的单型。 Haskell 的早期版本也是这样做的,然后 Mark Jones 发现推断类型变量的种类实际上非常容易。 Haskell 很快被修改为允许更高种类的类型变量,但 ML 从未赶上。

INRIA 的人员对 ML 进行了许多其他更改,我有点惊讶他们从未进行过此更改。当我在 ML 中编程时,我可能会喜欢拥有更高种类的类型变量。但是它们不存在,而且我不知道有什么方法可以对您正在谈论的示例进行编码,除非使用 functors

【讨论】:

  • 好吧,Ocaml 于 1996 年首次发布,当时 let-polymorphism 限制是确保完整类型推断和主体类型的简单方法。我不知道您对“相当简单”的引用是什么,但是仅在 1999 中找到了 rank-2 多态性的类型重建。当然,对于 3 级及更高级别是无法确定的(同上)。
  • @huitseeker:问题不在于 rank-2 类型(在 Haskell 中嵌套 forall 量词的位置),而是关于高阶类型(嵌套 -> 的位置)。跨度>
  • “深层原因”在herehere 以及轻量级更高种类多态性的page 21.1 别名问题部分中进行了解释。 Scala 的 DOT 中 HKT 的细化(抽象类型)模型,也是exhibited the 推理问题。抽象依赖类型encapsulate to the type of the signature.
【解决方案2】:

您可以在 OCaml 中做类似的事情,使用模块代替类型,使用函子(高阶模块)代替高阶类型。但它看起来更丑,而且没有类型推断能力,所以你必须手动指定很多东西。

module type Type = sig
  type t
end

module Char = struct
  type t = char
end

module List (X:Type) = struct
  type t = X.t list
end

module Maybe (X:Type) = struct
  type t = X.t option
end

(* In the following, I decided to omit the redundant
   single constructors "Id of ...", "Compose of ...", since
   they don't help in OCaml since we can't use inference *)

module Id (X:Type) = X

module Compose
  (F:functor(Z:Type)->Type)
  (G:functor(Y:Type)->Type)
  (X:Type) = F(G(X))

let l : Compose(List)(Maybe)(Char).t = [Some 'a']

module Example2 (F:functor(Y:Type)->Type) (X:Type) = struct
  (* unlike types, "free" module variables are not allowed,
     so we have to put it inside another functor in order
     to scope F and X *)
  let iso (a:Compose(Id)(F)(X).t) : F(X).t = a
end

【讨论】:

  • 请添加对应问题的Fix类型构造函数的模块。
【解决方案3】:

嗯...我不是高阶类型的专家,也不是 Haskell 编程专家。 但这对于 F#(即 OCaml)来说似乎没问题,你可以使用这些吗:

type 'x id = Id of 'x;;
type 'f fix = Fix of ('f fix -> 'f);;
type ('f,'g,'x) compose = Compose of ('f ->'g -> 'x);;

最后一个我包装成元组,因为我没有想出更好的...

【讨论】:

  • 但是,我的意思是像 (list, option, int) compose 这样的东西,相当于 (int option) list
  • 我认为这可以使用选项类型来完成。在 F# 中,您还可以在 .NET 方式中使用多个类型参数: type compose = Compose of ('f -> 'g -> 'x);;但这可能不是真正的 OCaml 语法。
【解决方案4】:

你可以做到,但你需要做点小把戏:

newtype Fix f = In{out:: f (Fix f)}

您可以在之后定义 Cata:

Cata :: (Functor f) => (f a -> a) -> Fix f -> a
Cata f = f.(fmap (cata f)).out

这将为所有函子定义一个通用的变态,您可以使用它来构建自己的东西。示例:

data ListFix a b = Nil | Cons a b
data List a = Fix (ListFix a)
instance functor (ListFix a) where
fmap f Nil = Nil
fmap f (Cons a lst) = Cons a (f lst)

【讨论】:

  • 问题是关于 Ocaml 的函子(不同于 Haskell 的函子)。
  • 对不起,我误读了这个问题。无论如何,希望这对接触它的人有所帮助
猜你喜欢
  • 1970-01-01
  • 2012-09-22
  • 1970-01-01
  • 1970-01-01
  • 2013-12-01
  • 2022-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多