从GHC 7.6 的文档中:
您通常甚至根本不需要SPECIALIZE编译指示。编译模块M时,GHC的优化器(带有-O)自动考虑M中声明的每个顶级重载函数,并将其专门化为M中调用它的不同类型。优化器还考虑每个导入的INLINABLE重载函数,并将其专门用于M中不同类型的调用。
和
此外,给定函数f的SPECIALIZE编译指示,GHC将自动为f调用的任何类型类重载函数创建专用化,如果它们与SPECIALIZE编译指示在同一模块中,或者它们是不可插入的;等等。
因此,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
在没有标记为可以内联和2)simonpj表示,有一些内联回事票代码,而是从核心我的示例显示没有内联函数(特别是,我无法摆脱第二个Foo
构造函数,否则就无法使用GHC内联的东西)。
plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2
,会发生什么情况,以便在呼叫站点完全应用LHS?它会内联,然后开始专业化吗?
plus
由于这些链接,我最初曾要求完全应用,但实际上我的专业化程度较低:对的调用plus
也不是专门的。我对此没有任何解释,但打算将其留给另一个问题,或者希望在回答这个问题时得到解决。