Ответ 1
Я переписал ваши функции, чтобы избежать какой-либо явной рекурсии и удалил некоторые избыточные операции, вычисляющие смещения. Это скомпоновано гораздо лучше, чем ваши оригинальные функции.
Core, кстати, вероятно, лучший способ проанализировать ваш скомпилированный код для такого профилирования. Используйте ghc -ddump-simpl
, чтобы увидеть сгенерированный вывод ядра, или такие инструменты, как ghc-core
import Control.Monad.Primitive
import Control.Monad.ST
import Data.Int
import qualified Data.Vector.Unboxed.Mutable as M
import qualified Data.Vector.Unboxed as U
type MVI1 s = M.MVector (PrimState (ST s)) Int
findYP :: MVI1 s -> Int -> ST s Int
findYP fp offset = do
y0 <- M.unsafeRead fp (offset+0)
y1 <- M.unsafeRead fp (offset+2)
return $ max (y0 + 1) y1
findSnakes :: U.Vector Int32 -> MVI1 s -> Int -> Int -> (Int -> Int -> Int) -> ST s ()
findSnakes a fp k0 ct op = U.mapM_ writeAt $ U.iterateN ct (`op` 1) k0
where writeAt k = do
let offset = U.length a + k
yp <- findYP fp offset
M.unsafeWrite fp (offset + 1) (yp + k)
-- or inline findYP manually
writeAt k = do
let offset = U.length a + k
y0 <- M.unsafeRead fp (offset + 0)
y1 <- M.unsafeRead fp (offset + 2)
M.unsafeWrite fp (offset + 1) (k + max (y0 + 1) y1)
Кроме того, вы передаете U.Vector Int32
в findSnakes
, только для вычисления его длины и никогда не используйте a
снова. Почему бы не пройти по длине напрямую?