用GHC保证专业化

我正在努力确保GHC专门设计一个递归函数,以便所有东西都可以被拆箱。 完整的示例代码(以及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

好消息是,从看到被倾销的核心,我可以看到GHC已经在执行我感兴趣的专业化,这非常令人印象深刻。 不过,我希望能够指望它发生。 我担心如果我为该文件添加足够多的专用变体,或者如果我从另一个模块调用lookupSorted ,GHC最终可能倾向于生成一个小的可执行文件,而不是一个快速的可执行文件。

我的理解是SPECIALIZE pragma在这种情况下无助。 GHC目前不允许基于价值观点的专业化。 我很确定,如果我愿意为索引操作编写类型类型,那么我可以使SPECIALIZE工作。 我试图避免这种方法,因为除非没有其他解决方案,否则我不想引入类型类。

有没有办法强制GHC创建我的函数的这些专用变体? 此外,如果任何人对转储的核心文件有任何评论(如果有什么不是最佳的),我将不胜感激任何反馈。 谢谢。

- - 编辑 - -

更多地思考这个问题,似乎只需在lookupSorted上放置一个INLINE lookupSortedlookupSorted 。 GHC文档并不清楚INLINE和递归绑定内部letwhere子句之间的相互作用。 任何关于此的澄清,希望有一个支持来源,可能会有所帮助。


你最后的观察是正确的:如果你在一个函数上放置了一个INLINE注解,当它有足够的参数进行调用时,它将被内联。

足够的参数意味着你的函数的参数数量在=的左边(而不是右边的lambdas)。 这可以让你做类似的事情

foo op n  = y -> go n y
  where go acc i = … op … 

fooSpec1 = foo (+) 0 
fooSpec2 = foo (*) 1

并获得foo两个专业化,然后您可以多次调用,而无需进一步重复代码。

对于所有这些,在where发生什么并不重要,递归函数只会与foo一起内联。

(对不起,没有消息来支持。)

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

上一篇: Guarantee of Specialization with GHC

下一篇: Specializing related polymorphic functions without inlining