Java OCaml 的 GuardTypes 类比

Java GuardTypes analogy for OCaml

你好,Whosebug!

在Java实践中存在一些关于部分定义函数的问题。有时将错误处理与计算本身分开会很方便。我们可以使用一种称为 "Guard types" 或 "Guard decorators" 的方法。 考虑一个简单的综合示例:保护空引用。这可以借助下一个 class

public class NonNull<T> {
    public take() {
        return null != this.ref ? this.ref : throw new ExcptionOfMine("message");
    }

    public NotNull(T ref_) {
        this.ref     = ref_;
    }

    private T ref;       
}

问题是: 有没有办法在不触及其对象模型的情况下在 OCaml 中实现相同的 "Guard type"?我相信 OCaml 作为函数式编程语言拥有足够的抽象方法而不需要面向对象的技术。

有一个可选类型的概念,您可以在其上进行有效的模式匹配。示例:

let optional = Some 20
let value = 
  match optional with
  | Some v -> v
  | None -> 0

您可以使用抽象类型来获得相同的效果。 OCaml 对空指针没有问题。所以说你想以与上面相同的方式表示一个非空列表。即,您希望能够创建空值,但仅在用户尝试访问该值时才抱怨。

module G :
sig type 'a t 
    val make : 'a list -> 'a t 
    val take : 'a t -> 'a list 
end =
struct
    type 'a t = 'a list
    let make x = x
    let take x = if x = [] then raise (Invalid_argument "take") else x
end

以下是您使用该模块时的样子:

$ ocaml
        OCaml version 4.02.1

# #use "m.ml";;
module G :
  sig type 'a t val make : 'a list -> 'a t val take : 'a t -> 'a list end
# let x = G.make [4];;
val x : int G.t = <abstr>
# G.take x;;
- : int list = [4]
# let y = G.make [];;
val y : '_a G.t = <abstr>
# G.take y;;
Exception: Invalid_argument "take".

您可以使用简单的闭包

let guard_list v =
  fun () ->
    if v = [] then failwith "Empty list"
    else v

let () =
  let a = guard_list [1;2;3] in
  let b = guard_list [] in
  print_int (List.length (a ()));  (* prints 3 *)
  print_int (List.length (b ()))   (* throws Failure "Empty list" *)

或惰性值

let guard_string v = lazy begin
  if v = "" then failwith "Empty string"
  else v
end

let () =
  let a = guard_string "Foo" in
  let b = guard_string "" in
  print_endline (Lazy.force a);  (* prints "Foo" *)
  print_endline (Lazy.force b)   (* throws Failure "Empty string" *)