15

パイプ オペレータが次のように作成されている場合:

let (|>) f g = g f

そして、このように使用されます:

let result = [2;4;6] |> List.map (fun x -> x * x * x)

次に、List.Mapを取り、それを後ろに置きます (fun x -> x * x * x) [2;4;6] の位置については何も変更しません

したがって、次のようになります。

let result2 = [2;4;6] (fun x -> x * x * x) List.map

ただし、これは機能しません。

私は今初めてf#を学んでいます。f# に関する本を読んでいるときに、これが気になりました。後で何が欠けているかを知るかもしれませんが、とにかく尋ねることにしました。

私が何か大きなものを見逃していることは明らかです。パイプ演算子を簡単に再作成できるので。しかし、なぜそれが機能するのかわかりません。もっと学ぶと、すぐに恥ずかしい思いをするかもしれません。しかたがない。

4

4 に答える 4

19

パイプ演算子は、チェーンされたメソッド呼び出しの単なる構文糖衣です。これは、C# での linq 式の表現方法と非常によく似ています。

ここからの説明:

フォワード パイプ オペレーター 私はこの男が大好きです。Forward パイプ演算子は、単純に次のように定義されます。

let (|>) x f = f x

型シグネチャがあります:

'a -> ('a -> 'b) -> 'b

これは次のように変換されます: ジェネリック型 'a と、'a を取り、'b を返す関数が与えられた場合、入力に対する関数の適用を返します。

これを説明するのではなく、使用できる場所の例を挙げましょう。

// Take a number, square it, then convert it to a string, then reverse that string
let square x         = x * x
let toStr (x : int)  = x.ToString()
let rev   (x : string) = new String(Array.rev (x.ToCharArray()))

// 512 -> 1024 -> "1024" -> "4201"
let result = rev (toStr (square 512))

コードは非常に単純ですが、構文がいかに乱雑に見えるかに注目してください。やりたいことは、1 つの計算の結果を取得して、それを次の計算に渡すことだけです。一連の新しい変数を導入することで、これを書き直すことができます。

let step1 = square 512
let step2 = toStr step1
let step3 = rev step2
let result = step3

しかし今、これらすべての一時変数をまっすぐにしておく必要があります。(|>) 演算子が行うことは、値を取得して関数に「転送」することであり、基本的に関数呼び出しの前に関数のパラメーターを指定できます。これにより、ある関数の結果が次の関数に渡されるように、関数を一緒にパイプ処理できるようになるため、F# コードが大幅に簡素化されます。したがって、同じ例を使用すると、コードは次のように明確に記述できます。

let result = 512 |> square |> toStr |> rev

編集

F# では、メソッド呼び出しで実際に行っていることは、関数を取得し、それを後続のパラメーターに適用することです。したがって、この例では、にList.map (fun x -> x * x * x)適用され[2;4;6]ます。パイプ演算子が行うことは、パラメーターを逆の順序で取得し、アプリケーションでそれらを元に戻すことだけです。

関数:List.map (fun x -> x * x * x) パラメータ:[2;4;6]

標準の F# 呼び出し構文: fg

逆の F# 呼び出し構文: gf

標準:

let var = List.map (fun x -> x * x * x) [2;4;6]

逆:

let var = [2;4;6] |> List.map (fun x -> x * x * x)
于 2012-10-16T18:36:25.780 に答える
8

括弧|>は中置演算子であることを意味するため、例を書くことができます

let result = (|>) [2;4;6] (List.map (fun x -> x * x * x))

|>最初の引数を 2 番目の引数に適用するため、これは次と同等です。

let result = (List.map (fun x -> x * x)) [2;4;6]
于 2012-10-16T18:49:58.267 に答える
5

他の人が上で言ったように、基本的に result2 が何に解決されるかを誤解しています。実際には次のように解決されます

List.map (fun x -> x * x * x) [2;4;6]

List.map は、リスト内のすべての要素に適用する関数とリストの 2 つの引数を取ります。 (fun x -> x * x * x)は最初の引数で、[2;4;6]は 2 番目の引数です。

基本的には|>、右にあるものの終わりの後に左にあるものを置くだけです。

于 2012-10-16T19:26:58.987 に答える
3

の定義をfsiに入力し、型推論によって導出された演算子のシグネチャを見ると、つまり、関数に引数が与えられていることに|>気付くでしょう。val ( |> ) : 'a -> ('a -> 'b) -> 'b'a('a -> 'b)'b

ここで、このシグネチャを式に投影する[2;4;6] |> List.map (fun x -> x * x * x)と、が得られますList.map (fun x -> x * x * x) [2;4;6]。ここで、引数はリスト[2;4;6]であり、関数は1つの引数の関数に部分的に適用されList.map (fun x -> x * x * x)ます。

于 2012-10-16T18:52:49.083 に答える