具有约束的专业化

我有问题让GHC专门化一个带有类限制的函数。 我在这里有一个我的问题的最小例子:Foo.hs和Main.hs. 这两个文件编译(GHC 7.6.2, ghc -O3 Main )并运行。

注意: Foo.hs真的被剥夺了。 如果你想知道为什么需要约束,你可以在这里看到更多的代码。 如果我将代码放在单个文件中或做出许多其他较小的更改,GHC只需将该调用内联到plusFastCyc 。 这在实际代码中不会发生,因为plusFastCyc对于GHC内联而言过大,即使标记为INLINE 。 重点是专门调用plusFastCyc ,而不是内联它。 plusFastCyc在真实代码中的很多地方被调用,所以即使我强制GHC做这件事,重复这样一个大的函数也是不可取的。

感兴趣的代码是plusFastCyc中的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

Main.hs文件有两个驱动程序: vtTest ,它运行在〜3秒,和fcTest ,其在〜83秒当使用与-O3编译运行forall “d专业化。

核心显示,对于vtTest测试,添加代码被专用于Unboxed在载体Int S,等,而通用向量代码是用于fcTest 。 在第10行,你可以看到GHC确实编写了plusFastCyc的专用版本,与第167行的通用版本相比较。专业化的规则在第225行。我相信这条规则应该在第270行触发。( main6调用iterate main8 y ,所以main8plusFastCyc应该专用的地方。)

我的目标是让fcTestvtTest由专业plusFastCyc 。 我找到了两种方法来做到这一点:

  • 显式地调用inlineGHC.ExtsfcTest
  • 取下Factored m Int上约束plusFastCyc
  • 选项1并不令人满意,因为在实际的代码库中, plusFastCyc是一个经常使用的操作和一个非常大的函数,因此不应在每次使用时都内联。 相反,GHC应该调用plusFastCyc的专用版本。 选项2并不是真正的选择,因为我需要实际代码中的约束条件。

    我尝试了使用(而不是使用) INLINEINLINABLESPECIALIZE的各种选项,但似乎没有任何工作。 ( 编辑 :我可能已经删除了太多的plusFastCyc来使我的示例变小,所以INLINE可能会导致函数被内联。这在我的真实代码中不会发生,因为plusFastCyc非常大。)在这个特定示例中,我没有得到任何match_co: needs more casesRULE: LHS too complicated to desugar不能match_co: needs more cases (和这里)警告,尽管在最小化示例之前我得到了很多match_co警告。 据推测,“问题”是规则中的Factored m Int约束; 如果我对该约束进行更改,则fcTest运行速度与vtTest一样快。

    我正在做什么GHC只是不喜欢? 为什么GHC不会专注于plusFastCyc ,我plusFastCyc到这一点?

    UPDATE

    这个问题在GHC 7.8.2中仍然存在,所以这个问题仍然是相关的。


    GHC还提供了一个SPECIALIZE类型实例声明的选项。 我用Foo.hs的(扩展)代码尝试了这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
    

    但是,这种改变并没有达到理想的加速。 实现这种性能改进的方法是手动为类型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
    

    这需要在LANGUAGE添加OverlappingInstancesFlexibleInstances

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

    链接地址: http://www.djcxy.com/p/5675.html

    上一篇: Specialization with Constraints

    下一篇: Why does this Template Haskell work?