2013-02-20 70 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。實際上,如果您有更高級的函數來處理普遍存在的異常,這很有用。
相關問題