Ocaml中的高阶类型构造函数和函子

时间:2009-12-31 17:44:20

标签: functional-programming ocaml

可以使用以下多态函数

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

4 个答案:

答案 0 :(得分:32)

Haskell允许更高类型的类型变量。 ML方言,包括Caml,只允许类型变量“*”。翻译成普通英语,

  • 在Haskell中,类型变量g可以对应于“类型构造函数”,如MaybeIO或列表。因此,如果例如g xgMaybex,则Haskell示例中的Integer就可以了(行话:“良好的”)。

  • 在ML中,类型变量'g只能对应intstring这样的“地面类型”,而不能对应option之类的类型构造函数或list。因此,尝试将类型变量应用于其他类型时,永远不会正确。

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

INRIA的人们对ML做了很多其他的改变,我有点惊讶他们从来没有做过这个。当我用ML编程时,我可能喜欢使用更高级的变量。但它们不在那里,除了使用functors之外,我不知道如何编码你正在谈论的那些例子。

答案 1 :(得分:21)

您可以在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

答案 2 :(得分:0)

嗯......我不是高阶类型的专家,也不是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);;

我把最后一个包裹在元组中,因为我没有想出更好的东西......

答案 3 :(得分:-1)

你可以做到,但你需要做一些技巧:

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

这将为所有仿函数定义一个通用的catamorphism,您可以使用它来构建自己的东西。例如:

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)