17

F# を使用して関数型プログラミングを学習する最初の一歩を踏み出しましたが、Forward Pipe (|>) 演算子と Forward Composition (>>) 演算子に出くわしました。最初は、最終的な実行コードに影響を与えるのではなく、単なる砂糖だと思っていました (パイプが型推論に役立つことは知っていますが)。

しかし、私はこの SO 記事に出くわしました: 関数型プログラミングにおける「ポイントフリー」スタイルの利点と欠点は何ですか? これには2つの興味深い有益な答えがあります(物事を単純化する代わりに、「ポイントフリー」または「ポイントレス」スタイルを取り巻くワームの缶全体を開いた)これら(および他の読み物)からの私の持ち帰りは、ポイントフリーですが議論されている分野です。ランバと同様に、ポイントフリー スタイルは、用途に応じて、コードを理解しやすくしたり、はるかに難しくしたりできます。意味のある名前を付けるのに役立ちます。

しかし、私の質問は最初の回答に対するコメントに関するものです。

「コンポジションは、パイプライン処理のように中間値を生成する必要がないことをコンパイラーに明らかにすることで、GC の負荷を軽減する可能性があるように思えます。いわゆる「森林破壊」の問題をより扱いやすくするのに役立ちます。」

ガッシュは次のように答えます。

「コンパイルの改善に関する部分はまったく真実ではありません。ほとんどの言語では、ポイントフリー スタイルは実際にパフォーマンスを低下させます。Haskell が最適化に大きく依存しているのは、これらのコストを耐えられるものにする唯一の方法だからです。せいぜい、これらのコンビネータがインライン化され、同等の意味のあるバージョンが得られます。」</p>

誰でもパフォーマンスへの影響を拡大できますか? (一般的に、特に F# の場合) 私は、それが記述スタイルのものであり、コンパイラが両方のイディオムを同等のコードに分解すると想定していました。

4

1 に答える 1

35

この回答は F# 固有のものになります。他の関数型言語の内部がどのように機能するかはわかりませんが、それらが CIL にコンパイルされないという事実は大きな違いを生む可能性があります。

ここに 3 つの質問があります。

  1. を使用するとパフォーマンスにどのような影響があり|>ますか?
  2. を使用するとパフォーマンスにどのような影響があり>>ますか?
  3. 関数を引数付きで宣言する場合と引数なしで宣言する場合のパフォーマンスの違いは何ですか?

回答 (リンク先の質問の例を使用):

  1. と の間に違いはx |> sqr |> sumありsum (sqr x)ますか?

    いいえ、ありません。コンパイルされた CIL はまったく同じです (ここでは C# で表されています)。

    sum.Invoke(sqr.Invoke(x))
    

    (とは CIL メソッドではないInvoke()ためsqr、が使用されますが、ここでは関係ありません。)sumFSharpFunc

  2. と の間に違いは(sqr >> sum) xありsum (sqr x)ますか?

    いいえ、どちらのサンプルも上記と同じ CIL にコンパイルされます。

  3. と の間に違いはlet sumsqr = sqr >> sumありlet sumsqr x = (sqr >> sum) xますか?

    はい、コンパイルされたコードは異なります。引数を指定するとsumsqr、通常の CLI メソッドにコンパイルされます。ただし、指定しない場合はFSharpFunc、バッキング フィールドを持つ type のプロパティとしてコンパイルされ、そのInvoke()メソッドにはコードが含まれます。

    しかし、すべての効果は、ポイントフリー バージョンを呼び出すことは、1 つのフィールド ( FSharpFunc) をロードすることを意味します。これは、引数を指定した場合には行われません。しかし、最も極端な状況を除いて、パフォーマンスに測定可能な影響を与えるべきではないと思います。

于 2012-07-25T14:06:09.610 に答える