matarillo.com

The best days are ahead of us.

9.1 F# 1.0 -- Pipelines

2021-09-25 00:00:21

F# の特徴として最初に挙げられるようになったものは、最も単純なものでもあります。2003年にF# 標準ライブラリーに追加された「前方パイプライン」演算子です。

let (|>) x f = f x

カリー化された関数の適用とともに使えば、連鎖する関数の中に中間結果を通過させることができます。例えば:

[ 1 .. 10 ]
    |> List.map (fun x -> x *x)
    |> List.filter (fun x -> x % 2 = 0)

と書けるので、次のように書かなくてよくなります。

List.filter (fun x -> x % 2 = 0)
    (List.map (fun x -> x *x) [ 1 .. 10 ])

ML方言でのパイプライン記号の使用はF# が連想されることが多いのですが、実際には、(明らかにUNIXのパイプから記号論的なインスピレーションを受けて)1994年5月にTobias Nipkowによって開始されました[archives 1994; Syme 2011]。

……私(訳注:Marius Wenzel)は古いメールフォルダを掘り下げて、|>にまつわる真の物語を明らかにすることを約束しました。 それはIsabelle/MLで生まれたのですが、F# でも人気がでました。……

添付ファイルは、1994年4月から5月にかけての私たち3人 [Larry Paulson; Tobias Nipkow; Makarius Wenzel] のオリジナルのメールスレッドです。 その中で、今やML界隈の欠くことのできない部分となったそれを考えつきました。メール交換は、私の変更に対するLarryの返信として始まります。

……最終的に、|>という実際の名前を思いついたのは……Tobiasでした……

F# ではパイプライン記号の使用が特に重要です。型推論が左から右に伝播され、名前解決はプログラムの前方で使用可能な情報に基づいて行われるためです。 たとえば、次の例では、明示的な型注釈なしで型チェックに合格します。

let data = [ "one"; "two"; "three" ]

data |> List.map (fun s -> s.Length)

対照的に、次のコードは明示的な型注釈を必要とします。

let data = [ "one"; "two"; "three" ]

List.map (fun (s: string) -> s.Length) data

F# 標準ライブラリーでは2引数と3引数のパイプライン演算子も定義しました。例を示します。

let (||>) (x1, x2) f = f x1 x2

(0, data) ||> List.fold (fun count s -> count + s.Length)

インデックスへ戻る