2013-02-20 37 views
4

OCaml的选项类型在有可能不会返回任何东西的函数的情况下非常有用。但是当我在很多地方使用这种方法时,我发现在match ... with中始终处理SomeNone的情况非常麻烦。有没有其他方法可以解构OCaml中的选项类型?

例如,

let env2 = List.map (fun ((it,ie),v,t) -> 
    match t with 
    | Some t -> (v,t) 
    | None -> 
    begin 
     match it with 
     | Some it -> (v,it) 
     | None -> failwith "Cannot infer local vars" 
    end) ls_res in 

是否有任何其他的方式来解构以简洁的方式选项类型?

回答

9

对于简单的情况下,你可以一次满足几件事情:

match t, it with 
| Some t, _ -> (v, t) 
| None, Some it -> (v, it) 
| None, None -> failwith "Cannot infer local vars" 

这是我一直在做的事情。我被告知编译器对这个构造很好(它实际上并不会生成一对额外的对)。

+1

+1我也被告知编译器对这个构造很好,但有一天我看了一下程序集(我可以看看lambda代码,但是我已经知道一个汇编语言,所以对我来说实际上工作量较少),我很失望。令人印象深刻的优化在于看起来像被遗忘的明显情况。在这种情况下,两个调用'caml_alloc2'不应该在那里(但是):http://pastebin.com/EfFsxhCQ – 2013-02-20 20:44:19

+0

这是一个拖动,但我仍然喜欢简单情况下这种匹配的清晰度。 – 2013-02-20 21:08:19

+0

谢谢!这是最简洁和可读的答案。 – 2013-02-21 04:59:32

1

根据你想要做什么,你可以写很多东西来帮助处理这些事情。对于这种模式,我建议写类似如下:

let or_else opt1 opt2 = match opt1 with 
    | Some _ -> opt1 
    | None -> opt2 

然后重组你的代码为:

let env2 = List.map (fun ((it,ie),v,t) -> 
    match (or_else opt1 opt2) with 
    | Some t -> (v,t) 
    | None -> failwith "Cannot infer local vars") ls_res in 

如果你有超过这个数量的选项更多,那么你就可以折叠or_else在他们的名单:

let a = [None; None; Some 1; Some 2;];; 
List.fold a ~init:None ~f:or_else;; 
+0

谢谢!但我不知道这是否是惯用的ocaml ...:/ – 2013-02-20 14:44:45

+0

我想这可能不是,但我看不出为什么。 Jane Street的Core库在自己的'Option'类中定义为'first_some',所以它在标准库中,尽管我发现'or_else'更明显。 – Impredicative 2013-02-20 14:49:40

0
  • 选项单子(也可能是monad)。请注意,Haskell中的Just是OCaml中的Some,Haskell中的Nothing是OCaml中的Nonehttp://en.wikipedia.org/wiki/Option_type#The_option_monad
  • 高阶函数:default : 'a -> 'a option -> 'amap_option : ('a -> 'b) -> 'a option -> 'b optionor_else在另一个答案,map_some : ('a -> 'b option) -> 'a list -> 'b listconcat_some : 'a option list -> 'a list等我的名字可能不是标准。
  • 如果您遇到麻烦,请拨打unsome : 'a option -> 'a,let unsome = function Some a -> a | None -> raise Not_found。实际上,如果您有更高级的函数来处理普遍存在的异常,这很有用。
相关问题