2

冗長すぎると思われるため、これらのコードを短縮する方法を考えています

let get ename doc = 
  try Some (StringMap.find ename doc) with Not_found -> None;;

let get_double ename doc = 
  let element = get ename doc in
  match element with
    | None -> None
    | Some (Double v) -> Some v
    | _ -> raise Wrong_bson_type;;

let get_string ename doc = 
  let element = get ename doc in
  match element with
    | None -> None
    | Some (String v) -> Some v
    | _ -> raise Wrong_bson_type;;

let get_doc ename doc = 
  let element = get ename doc in
  match element with
    | None -> None
    | Some (Document v) -> Some v
    | _ -> raise Wrong_bson_type;;

つまり、基本的に、私はさまざまな種類の値を持っており、それらすべての種類の値をマップに入れています。

上記のコードは、対応するタイプの値をマップから取得するためのものです。私がしていることは、タイプごとに get があるということです。1 つのタイプの値を取得するには、a) を確認する必要があります。そこにあるかどうか。b)。それが実際にそのタイプであるかどうか、そうでない場合は例外を発生させます。

しかし、ご覧のとおり、上記のコードは冗長に見えます。各タイプの get 間の唯一の違いは、タイプ自体です。

このコードを短くするにはどうすればよいですか?

4

4 に答える 4

2

GADT を使用してそれを行うことができます。

次のような型を定義する場合expr:

type _ expr =
  | Document: document -> document expr
  | String: string -> string expr
  | Double: float -> float expr

次のような関数を書くことができますget:

let get : type v. v expr -> v = function
   Document doc -> doc
 | String s -> s
 | Double d -> d
于 2013-04-25T13:52:46.957 に答える
0

これらのエクストラクタ関数を使用できる場合:

let extract_double = function
  | Double v -> v
  | _ -> raise Wrong_bson_type

let extract_string = function
  | String v -> v
  | _ -> raise Wrong_bson_type

let extract_doc = function
  | Document v -> v
  | _ -> raise Wrong_bson_type

次に、高階関数にモナド スタイルを使用できます。これにより、 の元の定義を保持できますget

let return x = Some x

let (>>=) mx f = 
  match mx with
    | Some x -> f x
    | None -> None

let get_with exf ename doc =
  (get ename doc) >>= fun v -> 
  return (exf v)

let get_double = get_with extract_double
let get_string = get_with extract_string
let get_doc = get_with extract_doc

冗長性を減らし、一般的なバインドおよびリターン操作への副作用を抽象化します。

于 2013-04-26T06:41:22.943 に答える