[英]Ocaml abstract type and type inference
我对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,但表达式的类型为'a option
在我的应用我个人有T不仅仅是INT选项更复杂,我不想对外公开其内部结构。 但是,我想告诉OCaml编译器t实际上是一个选项 。 我怎样才能做到这一点?
如果您不想公开您的实现,但是您需要使类型与其他类型兼容,请编写函数以转换为这些类型/从这些类型转换:
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
保持抽象,这意味着您可以在不更改接口的情况下更改实现,前提是您在转换器中执行必要操作以保持其一致性。
最直接的方法是只使选项的内容类型为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
看来你想要的是让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
的实例的创建进行一些控制,但允许解构这样的实例(封装可以防止)。
除了这里已经存在的好答案之外,如果你只关心某些东西是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
重命名为与你的抽象相匹配的东西)
或者您可以提供抽象以允许正确类型的函数应用
module Test : sig
type t
val apply : (int option -> 'a) -> t -> 'a
val make_t : unit -> t
val ( @ ) : (int option -> 'a) -> t -> 'a
end = struct
type t = int option
let make_t () = Some 42
let apply f x = f x
let ( @ ) = apply
end
let do_work : 'a option -> unit = function
| Some x -> Printf.printf "Some\n"
| None -> Printf.printf "None\n"
let () =
let open Test in
do_work @ make_t ()
操作员可能有点太多但看起来更酷。 另外,您可能需要查看monad。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.