我在让GHC专门化具有类约束的函数时遇到问题。我有我的问题的一个小例子,在这里:Foo.hs和 Main.hs。这两个文件将编译(GHC 7.6.2,ghc -O3 Main)并运行。
注意:
Foo.hs真的被剥夺了。如果您想了解为什么需要约束,可以在此处查看更多代码。如果我将代码放在单个文件中或进行许多其他小的更改,GHC只会内联对的调用plusFastCyc。在实际代码中不会发生这种情况,因为plusFastCyc即使GHC标记为,也无法内联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
该Main.hs文件有两个驱动程序:vtTest,运行时间约为3秒,而fcTest使用-O3使用forall'd专业化条件进行编译,则运行时间约为83秒。
的核心显示了,对于vtTest测试,添加代码被专用于Unboxed在载体IntS,等,而通用向量代码是用于fcTest。第10行,你可以看到,GHC确实写的专用版本plusFastCyc,相比上线167对专业化的规则是上线225的通用版本,我相信这个规则会被触发线270(main6电话iterate main8 y,所以main8是plusFastCyc应该在哪里专门。)
我的目标是做到fcTest与vtTest专精一样快plusFastCyc。我发现了两种方法可以做到这一点:
inline来自GHC.Exts中的显式调用fcTest。- 取消对的
Factored m Int约束plusFastCyc。
选项1不能令人满意,因为在实际的代码库中,这plusFastCyc是一个经常使用的操作并且功能非常大,因此不应在每次使用时都内联它。相反,GHC应该调用的专用版本plusFastCyc。选项2并不是真正的选项,因为我需要实际代码中的约束。
我已经尝试了多种选择使用(而不是使用)INLINE,INLINABLE以及SPECIALIZE,但似乎没有任何工作。(编辑:plusFastCyc为了使我的示例变小,我可能去除了太多内容,因此INLINE可能导致函数内联。在我的真实代码中不会发生这种情况,因为plusFastCyc它太大了。)在此示例中,我不是收到任何match_co: needs more cases或RULE: LHS too complicated to desugar(和此处)警告,尽管match_co在最小化示例之前我收到了很多警告。大概,“问题”是Factored m Int规则中的约束;如果我对该约束进行更改,则fcTest运行速度与一样快vtTest。
我在做GHC不喜欢的事情吗?GHC为什么不专门研究plusFastCyc,我该怎么做?
更新
该问题在GHC 7.8.2中仍然存在,因此此问题仍然相关。
m,即M。这样就完成了工作,但是我无法在实际程序中专门研究特定的幻像类型,因为它们已经被具体化了。