@@ и |> приоритет операторов в OCaml - PullRequest
1 голос
/ 22 апреля 2020

Я пытаюсь понять 2 оператора 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_ipv4_hlen_version version buf?

Что о

let options_len = nearest_4 @@ Cstruct.len t.options

почему бы не let options_len = nearest_4 Cstruct.len t.options

?

Полагаю, это связано с приоритетом, я вспоминаю некоторые из этих вещей из Haskell, но я не Не знаю Haskell Я просто где-то читал.

Как узнать приоритет вещей?

если требуется больше контекста, эти 2 кода пришли от https://github.com/mirage/mirage-tcpip/blob/master/src/ipv4/ipv4_packet.ml

Ответы [ 2 ]

6 голосов
/ 22 апреля 2020

Обозначение |> отображается только при наличии нескольких приложений с вложенными функциями. Многие люди находят это:

 x |> f a |> g b c |> h d

легче читать, чем это:

 h d (g b c (f a x))

, потому что больше нет необходимости сопоставлять скобки мысленно, и потому что операции применяются в левой порядок справа налево (что вполне естественно для читателей английского языка sh и других языков слева направо).

Если вы знакомы с командными строками Unix, это может помочь подумать о Оператор |> аналогичен оператору Unix pipe |.

Оператор приложения с более низким приоритетом, такой как @@, также помогает избежать скобок (и их умственного сопоставления). Многие люди находят это:

f x @@ g a b @@ h c d

легче читать, чем это:

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)

и не эквивалентно тому, что вы написали.

Приоритет оператора определяется его первым символом , Это, в свою очередь, определяется таблицей в Разделе 7.7.1 руководства OCaml.

(Конечно, вам нужно очень внимательно прочитать текст перед таблицей, чтобы увидеть правило приоритета.)

Обновление

Полное раскрытие: я никогда не использую |> или @@ в своем собственном коде. У меня нет проблем с несколькими скобками, и я обычно использую let, чтобы разбить большое выражение на более мелкие части.

3 голосов
/ 22 апреля 2020

Оператор |> очень удобен. Это эквивалент трубы в оболочке. Это позволяет вам писать код следующим образом:

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 = AB 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))
...