私がいちばん好きなプログラミング構文、「パイプライニング」
(herecomesthemoon.net)- パイプライニングは、プログラミング言語においてコードの可読性と保守性を高める重要な機能
- データの流れを左から右、上から下へ自然に表現できるようにする方式
- Rust のような言語では、パイプライニングはコードの流れを明確にし、IDE の自動補完機能によって開発生産性を高める
- Haskell、Elm、SQL などさまざまな言語で適用され、builder パターンやメソッドチェイニングも一種のパイプライニングと見なされる
- 可読性、編集のしやすさ、IDE サポート、**バージョン管理ツール(diff、blame)**のすべてに良い影響がある
- 関数をネストする方式より簡潔で明確なコードを書けるため、協業と保守の面でも有利
私がいちばん好きなプログラミング構文、パイプライニング
パイプライニングとは?
- 前の値を受け渡すことで、引数リストの中の1つの引数を省略できる機能
- コードの可読性を高め、コメントを追加しやすくしてくれる
- データを中心に連続した処理を順番に適用する構文スタイル
- 関数型スタイルのコードでは
.map().filter().collect()のようなメソッドチェイニングの形でよく使われる - Rust では次のようなコードが代表的な例:
data.iter() .filter(|w| w.alive) .map(|w| w.id) .collect() - 逆にすべての関数をネストすると、次のように内側から外側へ読まなければならない構造になる:
collect(map(filter(iter(data), |w| w.alive), |w| w.id))
なぜパイプライニングが良いのか?
-
1. 可読性と保守性
- 上から下へ読みやすい → 人が読む順序と同じデータフロー
- 各行にコメントを付けやすい
- 長い行でも括弧のネストなしで簡潔かつ明確
-
2. 編集のしやすさ
- 途中に
.map()などの新しい関数を1行で簡単に追加できる git diffやgit blameでも変更追跡がすっきり表れる
- 途中に
-
3. IDE / LSP サポート
.キーを押したときに 自動補完リストが出る構造と相性が良い- 型を明確に把握していることが前提となる静的解析に有利
- この機能がきちんと動作するには、言語が静的型付けベースである必要がある(e.g. Rust, TypeScript)
SQL にもパイプライニングはある?
- SQL のネストした SELECT クエリをパイプラインスタイルに変えられるという提案がある
- 例:
FROM customer |> LEFT OUTER JOIN orders ON ... |> AGGREGATE COUNT(...) GROUP BY ... |> ORDER BY ... - 従来の SQL より 流れが明確で、可読性が向上
- 欠点:
SELECT文が上から外れることで返り値の型を把握しにくくなる可能性がある → 解決可能
Builder パターンとのつながり
- Rust の
Builder::new().option().option().build()のような形は典型的なパイプライン構造 - 任意設定をメソッドで構成しながら、コード追跡や変更管理がしやすい
Haskell におけるパイプライニング改善
- Haskell の
$、&,|>のような演算子は、関数合成の代わりにパイプラインを使えるようにする - 例の比較:
-- 기존 checkPalindromes content = unlines $ map (show . isPalindrome) $ lines $ map toLower content -- 개선 checkPalindromes content = content & map toLower & lines & map (show . isPalindrome) & unlines
Rust におけるパイプライニングの利点
- メソッドチェイニング、型推論、trait ベースの構造的拡張性がいずれもパイプライニングとうまく噛み合う
- Rust は関数型とオブジェクト指向の構文の長所だけを取り出したような構造を持ち、パイプライニングの利用が最も自然
結論
- パイプライニングは単なる構文ではなく、コードの流れ、編集性、協業にまで影響する中核機能
f(g(h(x)))のようなネストより、x |> h |> g |> fの構造のほうが人間にやさしい- パイプライニングは「1行に1つの処理」という単純なルールのもとで、自然な流れを表現できる最良の方法
「各パイプの断片は主要なデータを受け取り、1つの処理を行う。最後に明確な名前を付ければ、それが最も理想的なコード構造だ。」
11件のコメント
私がいちばん好きなプログラミング構文、"パイプライニング"
https://github.com/tc39/proposal-pipeline-operator
どんなテキストでも
改行やインデントが可読性に重要なのと
似た文脈だと思います。
LINQ最高!
Gleamもこれをサポートしているので、かなりすっきりコードが書けるんですよね。
ところで、本文にコードブロックが入っているからなのか、モバイルでもデスクトップレイアウトで表示されますね。
そういえば、elmでもできますね。
少量のデータや上の例のような簡単なレベルのコードでは、見た目も悪くないと思います。
ですが
map()の中にコードが少しずつ入り始めると……コードがだんだん太っていく傾向がありますし、言語や実装ライブラリによって影響はありますが、データ量が多くなると、単にデータ構造にデータを積んだり操作したりしながら処理するのに比べて、簡単に数千倍遅くなることもあるので、
それに、さらに好まなくなった新しい理由がもう一つできたのですが、スマホでこの記事を見たら、PCレベルの幅がそのまま維持されて文字サイズがゴマ粒みたいに小さくなってしまい、記事を読むのがとても大変だったからです T.T
基本的には好みではなく、わざわざああいう書き方をしようとはしません。
JSもください
|>ぺこぺこ|>がとてもきれいです私が一番嫌いな文法だ
stack traceが少しでもこじれていると、デバッグは最悪だ
マジそれな
Hacker Newsの意見
筆者はこれを "pipelining" と呼んでいるが、正しい用語は "method chaining" だと思う
個人的には、言語の機能セットを小さく保ち、素早く完成した機能セットに到達することを支持している
|>構文は、すべての言語が採用してほしいと思っているLispマクロは、チェーンされたコレクション演算子だけでなく、呼び出しチェーンの順序を決定できる一般的な解決策を提供する
この用語は fluent interface として学んだ。パイプライニングは別物だ
パイプライン演算子は部分適用の一種で、複数の引数を束縛して新しい関数を作り、その出力を別の関数に渡せる
Rの tidyverse ユーザーはすでにこれを使っている
パイプライニングはデバッグが難しい。例外処理も難しく、パイプラインに分岐を追加しなければならない
SQLの構文は不必要に複雑だ
|>構文には表現力がなく、視覚的ノイズを増やす筆者は「意味が構文に勝る」と主張しているが、実際には構文の好みに焦点を当てている
effect-ts はパイプラインと命令型コードの両方を書けるようにしている