微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

OCaml 选择部分应用参数

如何解决OCaml 选择部分应用参数

我正在使用 OCaml 发出 http 请求。为了构建标题,我最终得到了以下工作代码

let body =
  let headers = Header.init () in
  let headers =  Header.add headers "foo" "bar" in
  let uri = Uri.of_string "https://www.example.com/" in
  Client.get ~headers:headers uri >>= fun (resp,body) ->
  (* rest of client code irrelevant *)

然而,第 2 行和第 3 行冒犯了我(可能是因为我对 OCaml 很陌生)。

所以我认为这样的事情会奏效,并且不会冒犯我微妙的情感。

  let headers = Header.init |> Header.add "foo" "bar" in

但是,这无法编译,因为 Header.add 的第一个 arg 预计为 Header.t 类型,并且我提供了一个字符串。是否有语言功能可以选择部分应用哪些参数?我已经看到可以在 Jane Street core 和 Batteries 中找到的 flip 可以让我使用更好的语法;但是,如果我理解正确,这将翻转所有参数,我最终将首先传递值而不是键。

有没有办法选择部分应用哪个arg?例如,在 Scala 中,我们可以使用“占位符”_;

生成一个函数
val f1 = (v1: String,v2: String,v3: String) => 42
val f2 = f1("foo",_,"baz") // f2 is a String => Int
List("a","b","c").map(f1(_,"bar","baz")) // this is fine. 

感谢阅读。

解决方法

然而,第 2 行和第 3 行冒犯了我

我相信

let headers =  Header.add (Header.init ()) "foo" "bar" in

比您的代码更具可读性。否则,使用不同的名称,例如

let bareheaders = Header.init () in
let headers =  Header.add bareheaders "foo" "bar" in

如果不知道您使用的是哪个 HTTP 库,我无法解释输入错误。

您是否考虑过使用 Ocsigen 框架?

是否有语言功能可以选择部分应用哪些参数?

也许labels,或classes,或functors

,

首先,这些行不应该真的冒犯到您,这段代码没有任何问题,您只是在完善 header 的值。想象它是一个价值变化的历史。给同一个实体赋予不同的名称通常是一个坏主意,因为它会造成混淆(阅读您代码的人可能会假设您想要值的非线性历史)并且容易出错(您可能会不小心引用错误的版本)实体)。

话虽如此,当你有一个很长的这样的任务序列时,它会变得很烦人(至少因为它的重复性)。在这种情况下,我通常会即时引入一个小型 DSL,例如,

let (:=) property value header = Header.add header property value

现在我们可以分配几个属性,例如,

let setup = [
   "foo" := "bar";
   "joe" := "doe";
   ...
]

我们现在有一个函数列表,我们可以很容易地将它应用到我们的标题中,使用

let init_header cmds = List.fold cmds ~init:(Header.init ()) ~f:(|>)

或者,如果我们将所有内容放在一起,

let body = 
  let header = init_header [
   "foo" := "bar";
   "joe" := "doe";
  ] in
  ...

在这个特定的例子中,你可以只使用一个对的列表,而不是函数,例如,

 let header = init_header [
   "foo","bar";
   "joe","doe";
  ] in

但是使用函数的方法效果更好,因为它可以分配不同类型的值,只要最后您可以将其细化为类型为 header -> header 的函数。

作为奖励曲目,我们刚刚实现的内容称为 Writer monad :)

附言

有没有办法选择部分应用哪个arg?例如,在 Scala 中,我们可以使用“占位符” _ 生成一个函数;

当然,使用fun,例如

  let headers = 
    Header.init () |> fun hdr -> 
    Header.add hdr "foo" "bar" |> fun hdr -> 
    Header.add hdr "joe" "doe" |> fun hdr ->
    ... in

或者,如果我们从 Scala 翻译,那么

val f2 = f1("foo",_,"baz")

将会

let f2 = fun x -> f1 "foo" x "baz"

或者,更短的时间,

let f2 x = f1 "foo" x "baz"
,

您似乎在使用 Cohttp 模块。您可以定义一个辅助函数 header,用于从键/值对列表构建 Header.t

# let header = List.fold_left (fun h x -> (Cohttp.Header.add h (fst x) (snd x)))
                              (Cohttp.Header.init ());;
val header : (string * string) list -> Cohttp.Header.t = <fun>

这与现有的 to_list 函数相反(也许它以不同的名称存在,我找不到它)。然后就可以这样使用了:

# Cohttp.Header.to_list (header [("h1","a");("h2","b")]);;
- : (string * string) list = [("h1","a"); ("h2","b")]

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。