Как я могу заставить мое правило стрелять?
Я работаю над правилами слияния списков для fromListN
в Data.Primitive.Array
, и я немного застрял. Функция выглядит так:
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_short
и fromListN_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 #-}
Первое правило перезаписи, похоже, все в порядке. Вторая проблема с обратной записью - проблема. Кажется, я не могу заставить его стрелять. Может ли кто-нибудь предложить предложение?
Примечание. Я знаю, что я мог бы просто слиться с build
и augment
чтобы не писать, но это... не очень красивое зрелище.
Ответы
Ответ 1
Основная проблема, по-видимому, является ошибкой с моей стороны. В
"fillArrayN/list" [1] forall n mary xs i.
foldr (fillArray_go n mary) (fillArray_stop n) xs i = fillArrayN n mary xs i
foldr
- Data.Foldable.foldr
, который является методом класса и, следовательно, не работает с LHS правила. Фиксирование этой проблемы делает правило обратной записи работать в простых случаях.
К сожалению, когда fromListNArray
с augment
(что обычно происходит, когда оно применяется к прилагаемым спискам), правило не срабатывает по другой причине. GHC создает функцию для fillArray_go n mary
и не fillArray_go n mary
ее. Я до сих пор не понимаю, почему это происходит.