参数多态模块
Parametrically polymorphic modules
这是 monad 的简单 OCaml 模块类型:
module type Monad = sig
type 'a t
val return : 'a -> 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
end
我可以用任何特定的 monad 实例化它,例如 reader 某种类型的 monad r
:
module Reader_monad : Monad = struct
type 'a t = r -> 'a
let return a = fun _ -> a
let bind o f = fun x -> f (o x) x
end
而且我可以通过使用仿函数在类型 r
上对其进行参数化:
module type Readable = sig type r end
module Reader (R : Readable) : Monad = struct
type 'a t = R.r -> 'a
let return a = fun _ -> a
let bind o f = fun x -> f (o x) x
end
但是,后一种方法要求我为不同类型实例化仿函数的不同实例 r
。有什么方法可以定义 Monad
类型的“参数多态”模块,它可以提供像 return : 'a -> ('r -> 'a)
这样的参数多态函数?
我认为使用“单子家族”的单独模块类型或多或少可以获得我想要的东西:
module type Monad_family = sig
type ('c, 'a) t
val return : 'a -> ('c, 'a) t
val bind : ('c, 'a) t -> ('a -> ('c, 'b) t) -> ('c, 'b) t
end
module Reader_family : Monad_family = struct
type ('c, 'a) t = 'c -> 'a
let return a = fun _ -> a
let bind o f = fun x -> f (o x) x
end
但是如果我有大量关于 monad 的一般事实库,这将需要手动修改它以使用系列。然后一些 monad 由一对类型参数化(尽管我认为这可以由产品类型编码),等等。所以我宁愿避免这样做。
如果这不能直接实现,是否至少有一种方法可以在参数化多态函数中本地实例化模块 Reader
?我以为我可以用 first-class 模块做到这一点,但我天真的尝试
let module M = Reader(val (module struct type r = int end) : Readable) in M.return "hello";;
产生错误信息
Error: This expression has type string M.t
but an expression was expected of type 'a
The type constructor M.t would escape its scope
我不明白。类型 M.t
不等于 int -> string
吗?
我认为这是与 相同的问题,其中模块 M
的寿命不够长。如果您改写
# module M = Reader(struct type r = int end);;
# M.return "hello";;
- : string M.t = <fun>
这样就可以了。
另外,Reader
仿函数失去了一些您可能想要的类型等式。您可以通过这样定义来恢复它们:
module Reader (R : Readable) : Monad with type 'a t = R.r -> 'a = struct
type 'a t = R.r -> 'a
let return a = fun _ -> a
let bind o f = fun x -> f (o x) x
end
这是 monad 的简单 OCaml 模块类型:
module type Monad = sig
type 'a t
val return : 'a -> 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
end
我可以用任何特定的 monad 实例化它,例如 reader 某种类型的 monad r
:
module Reader_monad : Monad = struct
type 'a t = r -> 'a
let return a = fun _ -> a
let bind o f = fun x -> f (o x) x
end
而且我可以通过使用仿函数在类型 r
上对其进行参数化:
module type Readable = sig type r end
module Reader (R : Readable) : Monad = struct
type 'a t = R.r -> 'a
let return a = fun _ -> a
let bind o f = fun x -> f (o x) x
end
但是,后一种方法要求我为不同类型实例化仿函数的不同实例 r
。有什么方法可以定义 Monad
类型的“参数多态”模块,它可以提供像 return : 'a -> ('r -> 'a)
这样的参数多态函数?
我认为使用“单子家族”的单独模块类型或多或少可以获得我想要的东西:
module type Monad_family = sig
type ('c, 'a) t
val return : 'a -> ('c, 'a) t
val bind : ('c, 'a) t -> ('a -> ('c, 'b) t) -> ('c, 'b) t
end
module Reader_family : Monad_family = struct
type ('c, 'a) t = 'c -> 'a
let return a = fun _ -> a
let bind o f = fun x -> f (o x) x
end
但是如果我有大量关于 monad 的一般事实库,这将需要手动修改它以使用系列。然后一些 monad 由一对类型参数化(尽管我认为这可以由产品类型编码),等等。所以我宁愿避免这样做。
如果这不能直接实现,是否至少有一种方法可以在参数化多态函数中本地实例化模块 Reader
?我以为我可以用 first-class 模块做到这一点,但我天真的尝试
let module M = Reader(val (module struct type r = int end) : Readable) in M.return "hello";;
产生错误信息
Error: This expression has type string M.t
but an expression was expected of type 'a
The type constructor M.t would escape its scope
我不明白。类型 M.t
不等于 int -> string
吗?
我认为这是与 M
的寿命不够长。如果您改写
# module M = Reader(struct type r = int end);;
# M.return "hello";;
- : string M.t = <fun>
这样就可以了。
另外,Reader
仿函数失去了一些您可能想要的类型等式。您可以通过这样定义来恢复它们:
module Reader (R : Readable) : Monad with type 'a t = R.r -> 'a = struct
type 'a t = R.r -> 'a
let return a = fun _ -> a
let bind o f = fun x -> f (o x) x
end