我试图确保GHC专门递归函数,以便所有的东西都被拆箱。完整的示例代码(以及GHC核心转储)可在this gist中找到。有问题的功能如下:保证与GHC专业化
import Data.Bits
import qualified Data.Vector.Unboxed as UV
lookupSorted :: Ord a => (Int -> a) -> Int -> a -> Maybe Int
lookupSorted lookupIx len needle =
let !r = go 0 (len - 1)
in if r < 0 then Nothing else Just r
where
go :: Int -> Int -> Int
go !lo !hi = if lo <= hi
then
let !mid = lo + (unsafeShiftR (hi - lo) 1)
!val = lookupIx mid
in case compare val needle of
EQ -> mid
LT -> go (mid + 1) hi
GT -> go lo (mid - 1)
else (-1)
这是从任何排序容器查找的数值相比,可以索引到的算法。我想,以确保这两个功能是本专业版本是:
{-# NOINLINE lookupUnboxedWord #-}
lookupUnboxedWord :: UV.Vector Word -> Word -> Maybe Int
lookupUnboxedWord v w = lookupSorted (UV.unsafeIndex v) (UV.length v) w
{-# NOINLINE lookupUnboxedDouble #-}
lookupUnboxedDouble :: UV.Vector Double -> Double -> Maybe Int
lookupUnboxedDouble v w = lookupSorted (UV.unsafeIndex v) (UV.length v) w
好消息是,从看the dumped core,我可以看到,GHC已经执行,我很感兴趣的专业化。这非常令人印象深刻。不过,我希望能够指望它发生。我担心,如果我为该文件添加足够多的专用变体,或者如果我从另一个模块中调用lookupSorted
,GHC可能最终倾向于生成一个小型可执行文件而不是一个快速文件。
我的理解是SPECIALIZE
编译在这种情况下不起作用。 GHC目前does not allow specialization based on value arguments。我很确定,如果我愿意为索引操作编写类型类型,那么我可以使SPECIALIZE
工作。我试图避免这种方法,因为除非没有其他解决方案,否则我不想引入类型类。
有没有办法强制GHC创建我的函数的这些专门变体?此外,如果任何人对转储的核心文件有任何评论(如果有什么不是最佳的),我将不胜感激任何反馈。谢谢。
---- ----编辑
更多这方面的思考,好像它可能是足够简单地把一个INLINE
编译上lookupSorted
。 GHC文档不清楚INLINE
和let
或where
子句中的递归绑定之间的相互作用。任何关于此的澄清,希望有一个支持来源,可能会有所帮助。