GHC 7.6 のドキュメントから:
そもそも、SPECIALIZEプラグマは必要ないことがよくあります。モジュールMをコンパイルすると、GHCのオプティマイザー(-O付き)は、Mで宣言された各トップレベルのオーバーロード関数を自動的に考慮し、Mで呼び出されるさまざまな型に特化します。オプティマイザーは、インポートされた各INLINABLEオーバーロード関数も考慮します。 Mで呼び出されるさまざまな型に特化しています。
そして
さらに、関数fにSPECIALIZEプラグマが指定されると、GHCは、それらがSPECIALIZEプラグマと同じモジュールにある場合、またはINLINABLEである場合、fによって呼び出されるすべての型クラスオーバーロード関数の特殊化を自動的に作成します。など、推移的に。
したがって、GHCはプラグマなしでマークされた一部/ほとんど/すべての(?)関数を自動的に特殊化する必要があります。明示的なプラグマを使用すると、特殊化は推移的です。私の質問は、自動専門化は推移的ですか?INLINABLE
具体的には、ここに小さな例があります:
Main.hs:
import Data.Vector.Unboxed as U
import Foo
main =
let y = Bar $ Qux $ U.replicate 11221184 0 :: Foo (Qux Int)
(Bar (Qux ans)) = iterate (plus y) y !! 100
in putStr $ show $ foldl1' (*) ans
Foo.hs:
module Foo (Qux(..), Foo(..), plus) where
import Data.Vector.Unboxed as U
newtype Qux r = Qux (Vector r)
-- GHC inlines `plus` if I remove the bangs or the Baz constructor
data Foo t = Bar !t
| Baz !t
instance (Num r, Unbox r) => Num (Qux r) where
{-# INLINABLE (+) #-}
(Qux x) + (Qux y) = Qux $ U.zipWith (+) x y
{-# INLINABLE plus #-}
plus :: (Num t) => (Foo t) -> (Foo t) -> (Foo t)
plus (Bar v1) (Bar v2) = Bar $ v1 + v2
GHCはへの呼び出しを特殊化しますが、パフォーマンスを低下させるインスタンスを特殊化しplus
ません。(+)
Qux
Num
ただし、明示的なプラグマ
{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}
ドキュメントが示すように推移的な特殊化(+)
が発生するため、特殊化され、コードは30倍速くなります(両方ともでコンパイルされます-O2
)。これは予想される動作ですか?(+)
明示的なプラグマで推移的に専門化することだけを期待すべきですか?
更新
7.8.2のドキュメントは変更されておらず、動作も同じであるため、この質問は依然として関連しています。
plus
たしませ simonpjは、いくつかは、チケットコード付きに行くがインライン化されることを示したが、よりコア)INLINABLE及び2としてマーク私の例は、どの関数もインライン化されなかったことを示しています(特に、2番目のFoo
コンストラクター、それ以外の場合はGHCインライン化されたもの)を取り除くことができませんでした。
plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2
LHSが呼び出しサイトで完全に適用されるようにを定義するとどうなりますか?インライン化された後、専門分野が導入されますか?
plus
plus