Not_found
OCamlのコードを書くときにいつも迷っていることを書いてみます。超初心者質問。いい知恵ください。Not_foundの扱いです。
コンテナにデータがあった場合→データを使う、と無かった場合→データを新規に作る、で分岐する処理は頻出すると思います。
まず普通にif文。
if TABLE.mem key xs then let item = TABLE.find key xs in ... else ...
これですと、探索を2回やってるわけで、遅そうです。
なので例外。
try let item = TABLE.find key xs in ... (*1*) with Not_found -> ...
これですと、(*1*)部分に他にNot_foundを投げるような処理があった場合、例外をもみ消してしまいます。よろしくない。
なのでoption。
match (try Some (TABLE.find key xs) with Not_found -> None) with | Some item -> ... | None -> ...
これですと、Someのところでメモリアロケートが発生しています。こんなことで一時オブジェクトを作るのはGC的によろしくない。
例外の種類を差し替えるとか……。
try let item = try TABLE.find key xs with Not_found -> raise My_Not_found_2 in ... (*1*) with My_Not_found_2 -> ...
……酷い無駄なコードな気がします。例外を投げたり受け止めたりというのは、普通に考えてメモリアロケートよりも重いわけで。
他の言語で行儀の悪いコードを書くなら、(*1*)でgotoしてとりあえずtryから出るようなことも可能なのですが、OCamlではそれはできません(ていうかOCaml文化以外の世界ならfindがNULLみたいな値を返して来ますよね、そもそも例外を使うような場面ではない)。一時オブジェクトを作ったりせずに、きれいにtryの範囲を限定するにはどうしたらいいでしょう。
え、一時オブジェクトを気にするな?いやまあそりゃあそうなんでしょうけど……。