我在让GHC专门化具有类约束的函数时遇到问题。我有我的问题的一个小例子,在这里:Foo.hs和 Main.hs。这两个文件将编译(GHC 7.6.2,ghc -O3 Main
)并运行。
注意:
Foo.hs
真的被剥夺了。如果您想了解为什么需要约束,可以在此处查看更多代码。如果我将代码放在单个文件中或进行许多其他小的更改,GHC只会内联对的调用plusFastCyc
。在实际代码中不会发生这种情况,因为plusFastCyc
即使GHC标记为,也无法内联INLINE
。关键是要专门针对plusFastCyc
,而不是内联它。plusFastCyc
在实际代码中的很多地方都调用了,因此即使希望强制GHC进行复制,也无法复制这么大的函数。
感兴趣的代码是plusFastCyc
in 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
在载体Int
S,等,而通用向量代码是用于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
。这样就完成了工作,但是我无法在实际程序中专门研究特定的幻像类型,因为它们已经被具体化了。