19

GHCのドキュメントによると:

... GHC は、関数が完全に適用されている場合にのみ関数をインライン化します。ここで、「完全に適用された」とは、関数定義の LHS に (構文的に) 表示されるのと同じ数の引数に適用されることを意味します。

与えられた例は、意味的に同等の 2 つの定義です。

comp1 :: (b -> c) -> (a -> b) -> a -> c
{-# INLINE comp1 #-}
comp1 f g = \x -> f (g x)

comp2 :: (b -> c) -> (a -> b) -> a -> c
{-# INLINE comp2 #-}
comp2 f g x = f (g x)

私の質問:

  1. この厳密な動作 (つまり、LHS の厳密な構文ビュー、最適化なしでインライン化された RHS) が得られるのは、INLINE プラグマが存在する場合のみですか?

  2. comp2INLINE プラグマが指定されていない場合、GHC は関数を のように変換しcomp1ますか?

  3. そうでない場合、なぜですか?一般に、コンパイラが関数のセマンティクスを調べて、部分的に適用する INLINE の量と場所を決定するのは難しすぎますか?

  4. let... inGHC がすべての関数をラムダ式の式のカスケードに変換し、LHS に束縛がない場合はどうなるでしょうか?

4

3 に答える 3

8

この例で、cそれ自体が関数型の場合はどうなるでしょうか? そのシナリオであなたの提案がどのように機能するかはわかりません。

いずれにせよ、関数のすべての引数を「前に引っ張る」ことを望まない場合は間違いなくあります。たとえば、次のようなコードがあるとします。

foo :: [Int] -> Int -> Int -> Int
foo list = let
  -- expensive precomputation here
  bar x y = ...
  in \ x y -> bar x y

部分的に適用してから、結果の関数を複数のアプリケーションに適用して、高価な事前計算作業を共有する必要がありますfoo代わりに として前に引き出した場合foo list x y、その高価な事前計算を共有することはできません。(私は深刻なアプリケーションでこのケースに遭遇しました。)

于 2012-07-27T16:03:50.973 に答える
6

これは良い質問です。私は Glasgow Haskell Compiler Inliner の秘密の論文をいくつか手がかりとして読みましたが、あまり見つかりませんでした。

ここで手ぶらで説明します。GHC は、実際には、「イータ拡張」と呼ばれる場合がありますcomp1comp2詳細については、このスレッドを参照してください: http://www.haskell.org/pipermail/glasgow-haskell-users/2011-October/020979.html

また、この eta 展開が厳密性を微妙に変更できるという問題もあります (またはありました)。ドキュメントへのこのコミットを参照してください(現在のものにはないようです。したがって、再構築されていないか、修正されているかのどちらかはわかりません):http://permalink.gmane.org/gmane .comp.lang.haskell.cvs.ghc/57721

いずれにせよ、上記のスレッドには、可能な限りその方向に進みたい理由を説明する SPJ があります。したがって、インライン化を改善するために意図的に別の方向に進むことは、少しばかげているように思えます。秘密の論文が議論しているように、無差別にインライン化することは最高のアイデアではありません.pragmaをさらに鈍いハンマーにして、そうすることが理にかなっているかどうかにかかわらず、関数がインライン化されるようにすることは、全体的に役立つことはもちろん、増加することは言うまでもありません.モジュールはさまざまなレベルの eta-shifted 関数を一度に保持する必要があるため、コードが肥大化します。

とにかく、コアGHC開発者ではない人として、それが私には最も可能性が高いと思われるものです.

于 2012-08-02T22:23:23.990 に答える