我对OCaml中的抽象类型有疑问。
假设我有一个隐藏某种类型的模块:
module Test : sig
type t
val make_t : unit -> t
end = struct
type t = int option
let make_t () = Some 42
end
我还有一个操作选项的功能:
let do_work : 'a option -> unit = function
| Some x -> Printf.printf "Some\n"
| None -> Printf.printf "None\n"
毫不奇怪,当我在 t 实例上调用 do_work 时,我遇到了类型错误:
let () =
do_work @@ Test.make_t ()
错误:此表达式的类型为Test.t,但表达式的类型为'一个选项
在我的应用程序中,我 t 比 int选项更复杂,我不想向外暴露其内部。但是,我想告诉OCaml编译器 t 实际上是某个选项。我怎样才能做到这一点?
答案 0 :(得分:4)
如果您不想公开您的实现,但是您需要使类型与其他类型兼容,请编写函数以转换为这些类型/从这些类型转换:
module Test : sig
type t
val make_t : unit -> t
val to_option : t -> int option (* Signature *)
end = struct
type t = int option
let make_t () = Some 42
let to_option t = t (* Implementation *)
end
然后,当您特别需要int option
:
let () =
Test.make_t ()
|> Test.to_option
|> do_work
这样,您的类型Test.t
保持抽象,这意味着您可以在不更改界面的情况下更改您的实现,只要您在转换器中执行必要的操作以保持其一致性。
答案 1 :(得分:4)
最直接的方法是只制作选项abstract的内容类型:
module Test :
sig
type t'
type t = t' option
val make_t : unit -> t
end =
struct
type t' = int
type t = t' option
let make_t () = Some 42
end
答案 2 :(得分:3)
您希望将t
设为私有类型:
module T : sig
type t = private int option
val mk: unit -> t
end = struct
type t = int option
let mk () = Some 42
end
let do_work: int option -> unit =
function
| None -> print_endline "None"
| Some i -> print_endline (string_of_int i)
let () =
do_work (T.mk () :> int option)
与抽象类型解决方案一样,它允许对t
实例的创建进行一些控制,但允许解构此类实例(封装可防止)。
答案 3 :(得分:2)
除了此处已有的好答案,如果您只关心某些内容是Some _
还是None
,您可以将其添加到您的界面:
module Test : sig
type t
val make_t : unit -> t
val is_some : t -> bool
end = struct
type t = int option
let make_t () = Some 42
let is_some = function
| Some _ -> true
| None -> false
end
(当然你可以将is_some
重命名为与你的抽象相匹配的东西)
答案 4 :(得分:1)
或者你可以提供一个抽象来允许在
中应用正确类型的函数ROLE_SUPER_ADMIN
操作员可能有点太多但看起来更酷。 另外,您可能需要查看monad。