编辑:我用一个更具体的例子使用组和环替换了模块类型A和B的抽象示例.
我使用众所周知的代数结构在一个例子中提出了我的问题.为组定义签名:
module type Group =
sig
type t
val neutral: t
val add: t -> t -> t
val opp: t -> t
end
并为包含许多有用操作的组定义签名,例如这里结合:
module type Extended_Group =
sig
include Group
val conjugate: t -> t -> t
end
绑定的实现仅取决于加法和相反,所以我不想为我定义的所有组明确地写它,所以我写下面的仿函数:
module F (G: Group) =
struct
include G
let conjugate x y = add (add x y) (opp x)
end
现在,假设您正在使用“扩展”组概念的其他结构,例如整数环:
module Z =
struct
(* Group *)
type t = int
let neutral = 0
let add x y = x+y
let opp x = -x
(* Ring *)
let m_neutral = 1
let mult x y = x*y
end
由于环是一个粒子组的情况,我们可以将仿函数F应用于它:
module Extended_Z = F(Z)
不幸的是,要将F应用于Z,Ocaml首先将Z的类型限制为Group,然后应用F.
一切都表现得就像我这样做:
module (Group_Z: Group) = Z
module Extended_Z = F(Group_Z)
因此,尽管Z.mult有意义,但编译器不知道Extended_Z.mult.我不想失去Extended_Z仍然是一个戒指的事实!当然,解决方案包括编写一个类似于F但是将Ring作为输入的仿函数F_Ring并不令人满意:我不想写F_Fields,F_VectorSpace等等.
这是我想要的:
>要么扩展模块的签名,要么暴露更多的值.
有可能以另一种方式执行,限制模块的签名(使用我用于Group_Z的语法),但我找不到放大签名的方法.这里会是这样的:
module (Ring_Extended_Z: Ring) = Extended_Z
>或者,一种定义多态仿函数的方法,即定义一个带有模块的仿函数F.
签名“至少组”并输出签名模块“至少扩展组”.当然,
这只有在包含时才有意义,这就是为什么我坚信OCaml中不存在这样的功能.
在互联网上搜索了几天的答案之后,我认为实现这一目标的正确方法实际上是以下方法:
(灵感来自Real World OCaml的第9章)
module F (G: Group) =
struct
let conjugate x y = ...
end
(与以前相同但没有包含)
然后在同一点执行所有包含:
module Extended_Z =
struct
include Z
include F(Z)
end
有人可以确认这是实现我想要的好方法,而且我的第一种方法不合适
OCaml的精神?更具体地说,有人可以确认选项1和2.在OCaml中确实不可能吗?
编辑:关于动态类型
在我看来,这仍然是静态打字,因为如果我写
module Extended_Z = F(Z: Ring)
OCaml仍然可以静态地键入这个具有签名Ring的模块,其中额外值为“conjugate”.它需要模块级别的多态性,
我理解的不存在,但我认为它可以存在而不会使类型系统动态化.
最佳答案 我在这个答案中分享了我发现实现我想要的两个部分令人满意的解决方案.
第一个是在我的问题末尾提出的那个,在代数结构的情况下可能是“好的”.
module type Group =
sig
type t
val neutral: t
val add: t -> t -> t
val opp: t -> t
end
module type Extended_Group =
sig
include Group
val conjugate: t -> t -> t
end
module F (G: Group) =
struct
let conjugate x y = G.add (G.add x y) (G.opp x)
end
module type Ring =
sig
include Group
val m_neutral: t
val mult: t -> t -> t
end
module Z =
struct
type t = int
let neutral = 0
let add x y = x+y
let opp x = -x
(* Ring *)
let m_neutral = 1
let mult x y = x*y
end
module Extended_Z =
struct
include Z
include F(Z)
end
在这种情况下,OCaml推断出的Extended_Z的签名“扩展”了签名环,实际上Extended_Z.mult在模块外部是可见的.
第二种解决方案使用了Andreas Rossberg和Ivg建议的模块级别的多态性模型.在代数结构的情况下,它不太令人满意,但对于我的实际问题,它是完美的.
module type Group_or_More =
sig
include Group
module type T
module Aux: T
end
module F (G: Group_or_More) =
struct
include G
let conjugate x y = add (add x y) (opp x)
end
module Z =
struct
type t = int
let neutral = 0
let add x y = x + y
let opp x = -x
module type T =
sig
val m_neutral: t
val mult: t -> t -> t
end
module Aux =
struct
let m_neutral = 1
let mult x y = x*y
end
end
module Extended_Z = F(Z) ;;
在这里,签名Group_or_More正好捕获了我的签名扩展另一个的想法.你把所有额外的东西放到辅助模块Aux中.但是,为了能够提供所需数量的辅助功能,您可以将此Aux模块的签名指定为组的一部分.
对于代数结构,它不太令人满意,因为Z和Extended_Z是较弱意义上的环:乘法由Z.Aux.mult和Extended_Z.Aux.mult访问.