我正在处理一个项目,我正在处理Prim类型类,我需要确保我编写的特定函数是专门的.也就是说,我需要确保当我调用它时,我得到一个函数的专用版本,其中
Prim字典被内联到专用定义中而不是在运行时传递.
幸运的是,这是GHC中非常了解的事情.你可以写:
{-# SPECIALIZE foo :: ByteArray Int -> Int #-}
foo :: Prim a => ByteArray a -> Int
foo = ...
Run Code Online (Sandbox Code Playgroud)
在我的代码中,这种方法运行良好.但是,由于类型类是开放的,因此可能存在Prim我在编写库时尚不知道的情况.这让我想到了手头的问题.GHC用户指南的文档SPECIALIZE
提供了两种使用方法.第一个是放在SPECIALIZE定义的网站上,就像我在上面的例子中所做的那样.第二个是将SPECIALIZEpragma放在导入函数的另一个模块中.作为参考,用户手册提供的示例是:
module Map( lookup, blah blah ) where
lookup :: Ord key => [(key,a)] -> key -> Maybe a
lookup = ...
{-# INLINABLE lookup #-}
module Client where
import Map( lookup )
data T = T1 | T2 deriving( Eq, Ord )
{-# SPECIALISE lookup :: [(T,a)] -> T -> Maybe a
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是这在我的代码中不起作用.该项目在github上,相关的行是:
要运行基准测试,请运行以下命令:
git submodule init && git submodule update
cabal new-build bench && ./dist-newstyle/build/btree-0.1.0.0/build/bench/bench
Run Code Online (Sandbox Code Playgroud)
当我按原样运行基准测试时,输出的一部分显示为:
Off-heap tree, Amount of time taken to build:
0.293197796
Run Code Online (Sandbox Code Playgroud)
如果我取消注释BTree.Compact的第151行,那么基准测试的那部分运行速度要快50倍:
Off-heap tree, Amount of time taken to build:
5.626834e-2
Run Code Online (Sandbox Code Playgroud)
值得指出的是,有问题的功能modifyWithM是巨大的.它的实现超过100行,但我认为这不应该有所作为.文件声称:
...将f的定义标记为INLINABLE,以便GHC保证展开展开,无论它有多大.
所以,我的理解是,如果专注于定义网站的工作,那么应该总是可以专注于呼叫网站.我会很感激那些比我更了解这种机器的人的见解,如果有什么不清楚的话,我很乐意提供更多的信息.谢谢.
编辑:我已经意识到在我发布的git提交中,基准代码存在问题.它重复插入相同的值.然而,即使在解决了这个问题之后,专业化问题仍然存在.