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。要获得一种类型的值,我必须看到 a)。是否存在;乙)。是否确实是那种类型,如果不是,则引发异常。

但是如您所见,上面的代码似乎是多余的。每种类型的 get 之间的唯一区别就是类型本身。

如何缩短此代码?

4

4 回答 4

2

你可以这样做:

let get_generic extract ename doc =
  let element = get ename doc in
  match element with
    | None -> None
    | Some v -> Some (extract v)

let get_double = get_generic (function Double v -> v | _ -> raise Wrong_bson_type)
let get_string = get_generic (function String v -> v | _ -> raise Wrong_bson_type)
let get_doc = get_generic (function Document v -> v | _ -> raise Wrong_bson_type)

编辑:删除多余的raise Wrong_bson_type(但它很难看):

let get_generic extract ename doc = try
  let element = get ename doc in
  match element with
    | None -> None
    | Some v -> Some (extract v)
with Match_failure _ -> raise Wrong_bson_type

let get_double = get_generic (fun (Double v) -> v)
let get_string = get_generic (fun (String v) -> v)
let get_doc = get_generic (fun (Document v)-> v)
于 2013-04-25T13:36:43.713 回答
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 回答
1

使用 GADT:

type _ asked = 
 | TDouble : float asked
 | TString : string asked
 | TDocument : document asked

let get : type v. v asked -> string -> doc StringMap.t -> v option = 
  fun asked ename doc ->
  try
    Some (match asked, StringMap.find ename doc with
         | TDouble, Double f -> f
         | TString, String s -> s
         | TDocument, Document d -> d)
  with Not_found -> None

let get_double = get TDouble
let get_string = get TString
let get_document = get TDocument
于 2013-09-25T12:56:36.930 回答
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

然后,您可以对高阶函数使用 monadic 样式,这样您就可以保留原始定义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 回答