我只是想知道如何缩短这些代码,因为我怀疑它太冗余了
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;;
所以,基本上,我有不同类型的值,并将所有这些值放入地图中。
上面的代码用于从地图中获取相应的值类型。我所做的是,对于每种类型,我都得到了。要获得一种类型的价值,我必须看到a)。是否存在; B)。是否确实是这种类型,如果没有,则提出异常。
但是你可以看到上面的代码似乎是多余的。每种类型的get之间唯一的区别就是类型本身。
如何缩短此代码?
答案 0 :(得分: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)
答案 1 :(得分: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
答案 2 :(得分: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
答案 3 :(得分: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
减少冗余并将副作用抽象为通用绑定和返回操作。