Functional programming 如何缩短此OCaml代码?
我只是想知道如何缩短这些代码,因为我怀疑它太冗余了Functional programming 如何缩短此OCaml代码?,functional-programming,ocaml,Functional Programming,Ocaml,我只是想知道如何缩短这些代码,因为我怀疑它太冗余了 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
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)。是否有,;b) 。不管它是否真的是那种类型,如果不是,就会引发一个异常
但正如您所看到的,上面的代码似乎是多余的。每个类型的get之间唯一的区别就是类型本身
如何缩短此代码?您可以这样做:
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)
编辑:
要删除冗余的升高错误的\u bson\u类型
(但它很难看):
您可以使用GADT来实现这一点: 如果您这样定义类型
expr
:
type _ expr =
| Document: document -> document expr
| String: string -> string expr
| Double: float -> float expr
let get : type v. v expr -> v = function
Document doc -> doc
| String s -> s
| Double d -> d
您可以编写如下函数get
:
type _ expr =
| Document: document -> document expr
| String: string -> string expr
| Double: float -> float expr
let get : type v. v expr -> v = function
Document doc -> doc
| String s -> s
| Double d -> d
如果您可以使用这些提取器功能:
let extract_double=函数
|双v->v
|->在类型上引发错误
让我们提取字符串=函数
|字符串v->v
|->在类型上引发错误
让我们提取函数
|文件v->v
|->在类型上引发错误
然后,您可以对高阶函数使用一元样式,这允许您保留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
减少冗余并将副作用抽象为通用绑定和返回操作。对于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
我们甚至可以删除冗余的
引发错误的\u bson\u type
我们还需要()来实现双v吗?喜欢有趣(双v)->……`是的,你需要括号。它很难看,因为模式匹配并不详尽。您认为此函数定义正确吗?例如,我不能执行异常错误\u bson\u type;;让f=funx->1 | uuu->提出错误的类型代码>匹配的语法错误抱歉,您必须使用函数
而不是乐趣
。抱歉,我的意思是使用get\u type样式,因为我希望用户明确地确定他想要什么。