Использование обозначения proc
для Arrow
, похоже, приводит к снижению производительности в моем проекте. Вот пример игры:
Мы определяем newtype для Coroutine (главным образом, копируем из Обобщение потоков в Coroutines) для представления машин Мили (т.е. функций которые несут какое-то состояние) с экземплярами Category
и Arrow
, напишите scan
функцию-обертку и evalList
функцию runner для списков.
Тогда мы имеем функции sumArr
и sumArr'
, где последний является первым, называемым в блоке proc
.
Компиляция с помощью stack ghc -- --make test.hs -O2
с использованием ghc-8.0.2 на OS X Я получаю время выполнения 0,087 сек для sumArr
и 3.263 с для sumArr'
(с большой нагрузкой на память).
Я хотел бы знать, действительно ли это вызвано использованием proc
, и если я могу что-то сделать, чтобы иметь нормальное поведение во время работы при использовании обозначения proc
(писать код стрелки без его мучительного). Спасибо.
{-# LANGUAGE Arrows #-}
{-# LANGUAGE BangPatterns #-}
import Prelude hiding (id, (.))
import Control.Arrow
import Control.Category
import qualified Data.List as L
newtype Coroutine i o = Coroutine { runC :: i -> (o, Coroutine i o) }
instance Category Coroutine where
id = Coroutine $ \i -> (i, id)
cof . cog = Coroutine $ \i ->
let (x, cog') = runC cog i
(y, cof') = runC cof x
in (y, cof' . cog')
instance Arrow Coroutine where
arr f = Coroutine $ \i -> (f i, arr f)
first co = Coroutine $ \(a,b) ->
let (c, co') = runC co a in ((c,b), first co')
scan :: (o -> t -> o) -> o -> Coroutine t o
scan f = go where
go i = Coroutine $ step i where
step a b = let !a' = f a b in (a', go a')
evalList :: Coroutine a b -> [a] -> [b]
evalList a = L.map fst . L.drop 1 . L.scanl' (\(_, acc) v -> let !x = runC acc v in x) (undefined, a)
sumArr, sumArr' :: Coroutine Int Int
sumArr = scan (\acc x -> let !newAcc = acc + x in newAcc) 0
sumArr' = proc v -> do sumArr -< v
testData :: [Int]
testData = [1..1000000]
main = print $ L.last $ evalList sumArr' testData