---
breaks: false
tags: public-tech
---
# OCaml の `|>` と `@@`
この記事は [OCaml Tips Advent Calendar 2022](https://adventar.org/calendars/8396) の6日目です。
OCaml には変わった演算子がたくさんあります。今回は `|>` と `@@` を紹介します。
この演算子はどちらも関数呼び出しを行う際に使用できる演算子で、次のように動作します。
ざっくり `|>` は Elixir の `|>` と同じで、`@@` は Haskell の `$` と同じです。
```ocaml=
(* 下 2 行は等価 *)
a b c
c |> a b
(* 下 2 行は等価 *)
a (b c)
a @@ b c
```
上の `|>` が特に便利で、例えばリストをどんどん変形していくときなんかに
括弧をネストすることなく直感的に書くことができます。
```ocaml=
(* リスト l のうち偶数の値だけ取り出して、2 倍して、文字列にして、スペース区切りで連結して、表示 *)
l
|> List.filter (fun x -> x mod 2 = 0)
|> List.map (( * ) 2)
|> List.map string_of_int
|> String.concat " "
|> print_endline
(* 上と等価で |> を使わない実装 *)
print_endline (String.concat " " (List.map string_of_int (List.map (( * ) 2) (List.filter (fun x -> x mod 2 = 0) l))))
```
`|>` を使うためには、流れていく(ように見える)引数が、呼び出す関数の一番最後の
引数である必要があります。つまり、例えば `l |> List.map f` と書けるためには、
`List.map` は一番最後の(つまり二番目の)引数としてリストを受け取らなければなりません。
OCaml の標準ライブラリは比較的、そのモジュールが定義するコンテナが一番最後の引数と
なるように定義されています。
例えば `List`・`Option`・`Map`・`String` などは、各々のコンテナが流れやすいように
関数が定義されています。ただし `Hashtbl` は、第一引数にコンテナを取る設計になって
いるほか、`Marshal` もデータを第一引数にとるため、注意が必要です。
ちなみに、OCaml では左辺の引数が右辺の関数の一番最後の引数になるのに対して、
Elixir の `|>` は一番始めの引数になります。
つまり Elixir で `l |> Enum.map(f)`
と書くと、これは `Enum.map(l, f)` と等価で、一番始めの引数になっています[^ocaml-elixir]。
[^ocaml-elixir]: このあたり、関数の部分適用が(ネイティブに)ある言語とない言語の違いという感じがします。個人的には OCaml の仕様のほうが generic な感じがして好きです。