我怎样才能解除我的规则?

时间:2018-03-22 05:28:35

标签: haskell ghc

我正在研究Data.Primitive.ArrayfromListN的列表融合规则,我有点卡住了。该函数如下所示:

fromListNArray :: Int -> [a] -> Array a
fromListNArray !n l =
  createArray n fromListN_too_short $ \mi ->
    let go i (x:xs)
          | i < n = writeArray mi i x >> go (i+1) xs
          | otherwise = fromListN_too_long
        go i [] = unless (i == n) fromListN_too_short
     in go 0 l
{-# NOINLINE fromListNArray #-}

fromListN_too_shortfromListN_too_long只是错误调用。

我的重写规则是

{-# RULES
"fromListNArray/foldr" [~1] forall n xs.
  fromListNArray n xs = createArray n fromListN_too_short $ \mary ->
    foldr (fillArray_go n mary) (fillArray_stop n) xs 0

"fillArrayN/list" [1] forall n mary xs i.
  foldr (fillArray_go n mary) (fillArray_stop n) xs i = fillArrayN n mary xs i
 #-}

定义助手

fillArrayN :: Int -> MutableArray s a -> [a] -> Int -> ST s ()
fillArrayN !n !mary xs0 !i0 = go i0 xs0
  where
    go i (x:xs)
      | i < n = writeArray mary i x >> go (i+1) xs
      | otherwise = fromListN_too_long
    go i [] = unless (i == n) fromListN_too_short
{-# NOINLINE fillArrayN #-}

fillArray_go :: Int
             -> MutableArray s a
             -> a
             -> (Int -> ST s ())
             -> Int
             -> ST s ()
fillArray_go !n !mary = \x r i ->
  if i < n
    then writeArray mary i x >> r (i + 1)
    else fromListN_too_long
{-# INLINE CONLIKE [0] fillArray_go #-}

fillArray_stop :: Int -> Int -> ST s ()
fillArray_stop !n = \i -> unless (i == n) fromListN_too_short
{-# INLINE [0] fillArray_stop #-}

第一条重写规则似乎没问题。第二个回写规则是问题所在。我似乎永远无法解雇它。有人可以提出建议吗?

注意:我知道我可以直接与buildaugment融合,以避免回写,但它......不是很好看。

1 个答案:

答案 0 :(得分:1)

主要问题似乎是我的错误。在

"fillArrayN/list" [1] forall n mary xs i.
  foldr (fillArray_go n mary) (fillArray_stop n) xs i = fillArrayN n mary xs i

foldrData.Foldable.foldr,这是一种类方法,因此不适用于规则的LHS。解决此问题会使回写规则在简单的情况下起作用。

不幸的是,当fromListNArrayaugment融合时(通常在将其应用于附加列表时发生),该规则因其他原因无法触发。 GHC为fillArray_go n mary创建了一个函数,并没有内联它。我仍然不明白为什么会这样。