约束专业化

cro*_*eea 155 haskell ghc

我遇到了让GHC专门化一个具有类约束的函数的问题.我有我的问题就在这里的一个小例子:Foo.hsMain.hs.这两个文件编译(GHC 7.6.2,ghc -O3 Main)并运行.

注意: Foo.hs真的被剥离了.如果您想了解为什么需要约束,可以在这里看到更多代码.如果我将代码放在一个文件中或进行许多其他微小的更改,GHC只是简单地将调用内联到plusFastCyc.这不会发生在实际代码中,因为plusFastCycGHC内联太大,即使在标记时也是如此INLINE.关键是要专门调用plusFastCyc,而不是内联它.plusFastCyc在真实代码的许多地方被调用,所以即使我可以强迫GHC这样做,也不可能复制这么大的功能.

感兴趣的代码是plusFastCycin Foo.hs,在这里转载:

{-# INLINEABLE plusFastCyc #-}
{-# SPECIALIZE plusFastCyc :: 
         forall m . (Factored m Int) => 
              (FastCyc (VT U.Vector m) Int) -> 
                   (FastCyc (VT U.Vector m) Int) -> 
                        (FastCyc (VT U.Vector m) Int) #-}

-- Although the next specialization makes `fcTest` fast,
-- it isn't useful to me in my real program because the phantom type M is reified
-- {-# SPECIALIZE plusFastCyc :: 
--          FastCyc (VT U.Vector M) Int -> 
--               FastCyc (VT U.Vector M) Int -> 
--                    FastCyc (VT U.Vector M) Int #-}

plusFastCyc :: (Num (t r)) => (FastCyc t r) -> (FastCyc t r) -> (FastCyc t r)
plusFastCyc (PowBasis v1) (PowBasis v2) = PowBasis $ v1 + v2
Run Code Online (Sandbox Code Playgroud)

Main.hs文件有两个驱动程序:vtTest运行时间约为3秒,fcTest使用forall'd specialization 时使用-O3编译时运行时间约为83秒.

核心显示了,对于vtTest测试,添加代码被专用于Unboxed在载体IntS,等,而通用向量代码是用于fcTest.在第10行,您可以看到GHC确实写了一个专门版本plusFastCyc,与第167行的通用版本相比.专业化的规则在第225行.我相信这条规则应该在第270行开始.(main6调用iterate main8 y,所以main8是哪里plusFastCyc应该专门.)

我的目标是通过专业化来提高fcTest速度.我找到了两种方法:vtTestplusFastCyc

  1. 显式调用inlineGHC.ExtsfcTest.
  2. 删除Factored m Int约束plusFastCyc.

选项1是不能令人满意的,因为在实际的代码库中plusFastCyc是一个经常使用的操作和一个非常大的函数,所以它不应该在每次使用时都内联.相反,GHC应该调用一个专门的版本plusFastCyc.选项2实际上不是一个选项,因为我需要实际代码中的约束.

我已经尝试了多种选择使用(而不是使用)INLINE,INLINABLE以及SPECIALIZE,但似乎没有任何工作.(编辑:我可能已经剥离了太多plusFastCyc让我的例子变小,所以INLINE可能导致函数被内联.这不会发生在我的真实代码中,因为plusFastCyc它太大了.)在这个特殊的例子中,我不是获得任何match_co: needs more casesRULE: LHS too complicated to desugar(和此处)警告,尽管match_co在最小化示例之前我收到了很多警告.据推测,"问题"是Factored m Int规则中的约束; 如果我对该约束进行更改,则fcTest运行速度最快vtTest.

我在做什么GHC只是不喜欢?为什么GHC不会专攻plusFastCyc,我该怎么做呢?

UPDATE

这个问题在GHC 7.8.2中仍然存在,所以这个问题仍然存在.

Die*_*las 5

GHC还为SPECIALIZE类型类实例声明提供了一个选项。我使用的(扩展)代码尝试了此操作,方法Foo.hs如下:

instance (Num r, V.Vector v r, Factored m r) => Num (VT v m r) where 
    {-# SPECIALIZE instance ( Factored m Int => Num (VT U.Vector m Int)) #-}
    VT x + VT y = VT $ V.zipWith (+) x y
Run Code Online (Sandbox Code Playgroud)

但是,此更改未实现所需的加速。确实实现了性能改进,是为具有相同功能定义的类型手动添加了一个专用实例VT U.Vector m Int,如下所示:

instance (Factored m Int) => Num (VT U.Vector m Int) where 
    VT x + VT y = VT $ V.zipWith (+) x y
Run Code Online (Sandbox Code Playgroud)

这就需要增加OverlappingInstancesFlexibleInstancesLANGUAGE

有趣的是,在示例程序中,即使您删除了每个SPECIALIZEINLINABLE杂注,重叠实例所获得的加速仍然保持。