繁体   English   中英

Ocaml抽象类型和类型推断

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM