Vic*_*let 5 ocaml types signature type-constraints
在我的代码中,我有一个数据库访问上下文,提供基本的读/写操作,称为CouchDB.ctx
.我的应用程序中的各种模块然后使用其他功能扩展该类,例如Async.ctx
.
我正在实现一个Cache
包裹Source
模块的模块.该Cache
模块的功能需要上下文参数和操作数据库.然后,一些调用Source
与上下文一起转发到模块.
我需要按照以下方式定义一个仿函数:
module CouchDB = struct
class ctx = object
method get : string -> string option monad
method put : string -> string -> unit monad
end
end
module AsyncDB = struct
class ctx = object
inherit CouchDB.ctx
method delay : 'a. float -> (ctx -> 'a monad) -> 'a monad
end
end
module type SOURCE = sig
class ctx = #CouchDB.ctx (* <-- incorrect *)
type source
val get : source -> ctx -> string monad
end
module Cache = functor(S:SOURCE) -> struct
class ctx = S.ctx
type source = S.source
let get source ctx =
bind (ctx # get source) (function
| Some cache -> return cache
| None ->
bind (S.get source ctx)
(fun data -> bind (ctx # put source data)
(fun () -> return data))
end
module SomeSource = struct
class ctx = AsyncDB.ctx
type source = string
let get s ctx =
ctx # async 300 (some_long_computation s)
end
module SomeCache = Cache(SomeSource)
Run Code Online (Sandbox Code Playgroud)
问题是我无法表达Source
模块使用的上下文应该是子类型的事实CouchDB.ctx
.上面的代码返回错误:
A type variable is unbound in this type declaration.
In type #CouchDB.ctx as 'a the variable 'a is unbound
Run Code Online (Sandbox Code Playgroud)
如何表达此类型约束?
[过时...
您可以获得的最接近的是将签名定义为:
module type SOURCE = sig
type 'a ctx = 'a constraint 'a = #CouchDB.ctx
type source
val get : source -> 'a ctx -> string
end
Run Code Online (Sandbox Code Playgroud)
但当然,你也可以写:
module type SOURCE = sig
type source
val get : source -> #CouchDB.ctx -> string
end
Run Code Online (Sandbox Code Playgroud)
编辑:请注意,OCaml使用对象的结构类型.这意味着即使你想要,你也不能比上面的限制更多.它甚至不限制get
作为实例CouchDB.ctx
或派生类的参数 - 任何具有(至少)相同方法的对象都是兼容的.即使你写作
val get : source -> CouchDB.ctx -> string
Run Code Online (Sandbox Code Playgroud)
您可以传递任何具有相同方法的对象.该类型CouchDB.ctx
只是特定结构对象类型的缩写,恰好匹配由同名类生成的对象.它不仅限于此.而且可以肯定:这被视为一项功能.
======]
编辑2:通过扩展示例,我现在可以看到您想要的和原因.不幸的是,这在OCaml中是不可能的.你需要部分抽象的类型.也就是说,你需要能够写作
module type SOURCE = sig
type ctx < CouchDB.ctx
...
end
Run Code Online (Sandbox Code Playgroud)
这在OCaml中不可用.但是,如果您愿意在签名中提供明确的upcast,则可以关闭:
module type SOURCE = sig
type ctx
val up : ctx -> CouchDB.ctx
type source = string
val get : source -> ctx -> string monad
end
Run Code Online (Sandbox Code Playgroud)
然后,在Cache
,你必须替换ctx#get
with的出现(S.up ctx)#get
,同样替换ctx#put
.
module Cache = functor (S:SOURCE) -> struct
type ctx = S.ctx
type source = S.source
let get source ctx =
bind ((S.up ctx)#get source) ...
end
module SomeSource = struct
type ctx = AsyncDB.ctx
let up ctx = (ctx : ctx :> CouchDB.ctx)
type source = string
let get s ctx = ...
end
module SomeCache = Cache (SomeSource)
Run Code Online (Sandbox Code Playgroud)
请注意,我type source = string
在签名中也是透明的SOURCE
.没有它,我无法看到如何ctx#get source
在Cache
仿函数中进行类型检查.
归档时间: |
|
查看次数: |
2164 次 |
最近记录: |