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样式,因为我希望用户明确地确定他想要什么。