Functional programming @@和|>;OCaml中的运算符优先级

Functional programming @@和|>;OCaml中的运算符优先级,functional-programming,ocaml,Functional Programming,Ocaml,我试图理解两个OCaml操作符:@和|> 我知道x |>f只是f(x),但它为什么存在呢?我不明白为什么。与@相同,正如我所理解的,这只是正常的函数应用程序 例如: match get_ipv4_hlen_version buf |> version with | 0x40 -> Ok buf | n -> Error (Printf.sprintf "IPv4 presented with a packet that claims a differe

我试图理解两个OCaml操作符:
@
|>

我知道
x |>f
只是
f(x)
,但它为什么存在呢?我不明白为什么。与
@
相同,正如我所理解的,这只是正常的函数应用程序

例如:

 match get_ipv4_hlen_version buf |> version with
      | 0x40 -> Ok buf
      | n -> Error (Printf.sprintf "IPv4 presented with a packet that claims a different IP version: %x" n)
为什么不直接编写
get\u ipv4\u hlen\u version buf

那怎么办

let options_len = nearest_4 @@ Cstruct.len t.options
为什么不
let options\u len=最近的\u 4 Cstruct.lent.options

?

我想这与优先权有关,我从哈斯克尔那里回忆起一些事情,但我不知道哈斯克尔,我只是在某个地方读过

我怎么知道事情的先后顺序


如果需要更多的上下文,这两个代码来自只有当您有多个嵌套函数应用程序时,
的符号值才会出现。许多人发现:

 x |> f a |> g b c |> h d
f x @@ g a b @@ h c d
比这更容易阅读:

 h d (g b c (f a x))
f x ((g a b) (h c d))
因为不再需要在心理上匹配括号,而且操作是按从左到右的顺序进行的(这对于英语和其他从左到右的语言的读者来说是很自然的)

如果您熟悉Unix命令行,那么将
操作符与Unix管道操作符
类似可能会有所帮助

@
这样的低优先级函数应用运算符也有助于避免括号(以及括号的心理匹配)。许多人发现:

 x |> f a |> g b c |> h d
f x @@ g a b @@ h c d
比这更容易阅读:

 h d (g b c (f a x))
f x ((g a b) (h c d))
您对@的示例是错误的。这个

let options_len = nearest_4 @@ Cstruct.len t.options
相当于:

let options_len = nearest_4 (Cstruct.len t.options)
和你写的不一样

运算符的优先级由其第一个字符决定。这又由OCaml手册中的表定义

(当然,您需要非常仔细地阅读表格前面的文本,以查看优先级规则。)

更新


完全披露:我从不在自己的代码中使用
|>
@
。我对几个括号没有问题,我通常使用
let
将一个大表达式分解成更小的部分。

只有在有多个嵌套函数应用程序时才会显示
的符号值。许多人发现:

 x |> f a |> g b c |> h d
f x @@ g a b @@ h c d
比这更容易阅读:

 h d (g b c (f a x))
f x ((g a b) (h c d))
因为不再需要在心理上匹配括号,而且操作是按从左到右的顺序进行的(这对于英语和其他从左到右的语言的读者来说是很自然的)

如果您熟悉Unix命令行,那么将
操作符与Unix管道操作符
类似可能会有所帮助

@
这样的低优先级函数应用运算符也有助于避免括号(以及括号的心理匹配)。许多人发现:

 x |> f a |> g b c |> h d
f x @@ g a b @@ h c d
比这更容易阅读:

 h d (g b c (f a x))
f x ((g a b) (h c d))
您对@的示例是错误的。这个

let options_len = nearest_4 @@ Cstruct.len t.options
相当于:

let options_len = nearest_4 (Cstruct.len t.options)
和你写的不一样

运算符的优先级由其第一个字符决定。这又由OCaml手册中的表定义

(当然,您需要非常仔细地阅读表格前面的文本,以查看优先级规则。)

更新


完全披露:我从不在自己的代码中使用
|>
@
。我对几个括号没有问题,我通常使用
let
将一个大表达式分解成更小的部分。

操作符
|>
非常方便。它相当于壳体中的管道。它允许您编写如下代码:

let make_string n = 
  Array.init n float_of_int
  |> Array.map (fun x -> x -. 0.5 *. (float_of_int (n-1))) 
  |> Array.map (fun x -> Printf.sprintf "-- %10.6f --" x)
  |> Array.to_list
  |> String.concat "\n"
in
make_string 5

(* Output:
--  -2.000000 --
--  -1.000000 --
--   0.000000 --
--   1.000000 --
--   2.000000 --
*)
在本例中,以
|>
开头的每一行都会获取上一次转换的输出,因此我们可以看到数据转换的流程,就像在Bash中编写类似

ls | grep txt | sort | uniq
@
操作符是“向后管道”。它允许删除会降低代码可读性的括号。例如,我们想制作一系列矩阵积,比如C=a.B.C.D。你想让代码与数学公式保持一致,所以你想以相同的顺序编写它。如果
mm A B
对A和B进行矩阵乘法,那么我们可以编写

let mat_C = 
   mm mat_A @@ mm mat_B @@ mm mat_C mat_D
而不是

let mat_C = 
   mm mat_A (mm mat_B (mm mat_C mat_D))

|>
操作符非常方便。它相当于壳体中的管道。它允许您编写如下代码:

let make_string n = 
  Array.init n float_of_int
  |> Array.map (fun x -> x -. 0.5 *. (float_of_int (n-1))) 
  |> Array.map (fun x -> Printf.sprintf "-- %10.6f --" x)
  |> Array.to_list
  |> String.concat "\n"
in
make_string 5

(* Output:
--  -2.000000 --
--  -1.000000 --
--   0.000000 --
--   1.000000 --
--   2.000000 --
*)
在本例中,以
|>
开头的每一行都会获取上一次转换的输出,因此我们可以看到数据转换的流程,就像在Bash中编写类似

ls | grep txt | sort | uniq
@
操作符是“向后管道”。它允许删除会降低代码可读性的括号。例如,我们想制作一系列矩阵积,比如C=a.B.C.D。你想让代码与数学公式保持一致,所以你想以相同的顺序编写它。如果
mm A B
对A和B进行矩阵乘法,那么我们可以编写

let mat_C = 
   mm mat_A @@ mm mat_B @@ mm mat_C mat_D
而不是

let mat_C = 
   mm mat_A (mm mat_B (mm mat_C mat_D))

这回答了你的问题吗?这回答了你的问题吗?“fx@@gab@@hcd”和你说的“fx((gab)(hcd))一样吗?它不是和‘fx(gab(hcd))一样吗?所以,也许它不那么容易阅读。好吧,你说得有道理!我测试了我的例子,所以我认为它是正确的。我相信这一点仍然有效(可能对于更简单的表达式)。而且,
fx((gab)(hcd))
fx(gab(hcd))
是同一个表达式,这些参数是不必要的:-)@PatJ第一个不部分适用于
g
?不像第二个?如果说
a
c
有副作用,这可能会有不同。@ghilesZ因为函数参数的求值顺序是未指定的,并且由于ocaml的自动部分应用,我转而认为,就语言而言,带有附加括号的版本和带有