Стиль против производительности с использованием векторов

Вот's код:

{-# LANGUAGE FlexibleContexts #-}

import Data.Int
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Generic as V

{-# NOINLINE f #-} -- Note the 'NO'
--f :: (Num r, V.Vector v r) => v r -> v r -> v r
--f :: (V.Vector v Int64) => v Int64 -> v Int64 -> v Int64
--f :: (U.Unbox r, Num r) => U.Vector r -> U.Vector r -> U.Vector r
f :: U.Vector Int64 -> U.Vector Int64 -> U.Vector Int64
f = V.zipWith (+) -- or U.zipWith, it doesn't make a difference

main = do
    let iters = 100
        dim = 221184
        y = U.replicate dim 0 :: U.Vector Int64
    let ans = iterate ((f y)) y !! iters
    putStr $ (show $ U.sum ans)

Я скомпилировал сghc 7.6.2 а также-O2и потребовалось 1,7 секунды, чтобы бежать.

Я пробовал несколько разных версий:f

f x = U.zipWith (+) xf x = (U.zipWith (+) x) . idf x y = U.zipWith (+) x y

Версия 1 совпадает с оригинальной, а версии 2 и 3 работают менее чем за 0,09 секунды (иINLINING f Безразлично»ничего не меняю).

Я также заметил, что если я сделаюf полиморфный (с любой из трех подписей выше), даже с "быстро" определение (то есть 2 или 3), оно замедляется ... ровно до 1,7 секунды. Это заставляет меня задуматься о том, возможно, исходная проблема связана с (отсутствием) логического вывода типа, хотя яm явно указав типы для типа Vector и типа элемента. I '

Я также заинтересован в добавлении целых чисел по модулю:q

newtype Zq q i = Zq {unZq :: i}

Как при добавленииInt64s, если я напишу функцию с каждым указанным типом,

h :: U.Vector (Zq Q17 Int64) -> U.Vector (Zq Q17 Int64) -> U.Vector (Zq Q17 Int64)

Я получаю на порядок лучшую производительность, чем если бы я оставил полиморфизм

h :: (Modulus q) => U.Vector (Zq q Int64) -> U.Vector (Zq q Int64) -> U.Vector (Zq q Int64)

Но я долженпо крайней мере быть в состоянии удалить определенный тип фантома! Это должно быть составлено, так как яЯ имею дело с.newtype

Вот мои вопросы:

Откуда идет замедление?Что происходит в версиях 2 и 3f это влияет на производительность в любом случае? Мне кажется ошибкой, что (что составляет) стиль кодирования может повлиять на производительность, как это. Есть ли другие примеры за пределами Vector, где частичное применение функции или другой стилистический выбор влияют на производительность?Почему полиморфизм замедляет меняпорядок величины, не зависящий от того, где полиморфизм (т.е. в векторном типе, вNum тип, оба или фантомный тип)? Я знаю, что полиморфизм делает код медленнее, но это смешно. Есть ли взломать вокруг этого?

РЕДАКТИРОВАТЬ 1

Я подалвопрос со страницей векторной библиотеки. Я нашелВыпуск GHC касательно этой проблемы.

EDIT2

Я переписал вопрос после получения некоторого понимания от @kqr 'ответ. Ниже оригинал для справки.

-------------- ОРИГИНАЛЬНЫЙ ВОПРОС --------------------

Вот's код:

{-# LANGUAGE FlexibleContexts #-}

import Control.DeepSeq
import Data.Int
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Generic as V

{-# NOINLINE f #-} -- Note the 'NO'
--f :: (Num r, V.Vector v r) => v r -> v r -> v r
--f :: (V.Vector v Int64) => v Int64 -> v Int64 -> v Int64
--f :: (U.Unbox r, Num r) => U.Vector r -> U.Vector r -> U.Vector r
f :: U.Vector Int64 -> U.Vector Int64 -> U.Vector Int64
f = V.zipWith (+)

main = do
    let iters = 100
        dim = 221184
        y = U.replicate dim 0 :: U.Vector Int64
    let ans = iterate ((f y)) y !! iters
    putStr $ (show $ U.sum ans)

Я скомпилировал сghc 7.6.2 а также-O2и потребовалось 1,7 секунды, чтобы бежать.

Я пробовал несколько разных версий:f

f x = U.zipWith (+) xf x = (U.zipWith (+) x) . U.forcef x = (U.zipWith (+) x) . Control.DeepSeq.force)f x = (U.zipWith (+) x) . (\z -> z `seq` z)f x = (U.zipWith (+) x) . idf x y = U.zipWith (+) x y

Версия 1 совпадает с оригинальной, версия 2 запускается за 0,111 секунды, а версии 3-6 - менее 0,09 секунды (иINLINING f Безразлично»ничего не меняю).

Таким образом, замедление порядка величины происходит из-за лени, так какforce помогло, но яЯ не уверен, откуда приходит лень. Распакованные типыне позволено быть ленивым, верно?

Я пытался написать строгую версиюiterateдумая, что сам вектор должен быть ленивым

{-# INLINE iterate' #-}
iterate' :: (NFData a) => (a -> a) -> a -> [a]
iterate' f x =  x `seq` x : iterate' f (f x)

но с бессмысленной версиейfэто нене поможет вообще.

Я также заметил кое-что еще, что могло быть просто совпадением и красной селедкой: если я сделаюf полиморфный (с любой из трех подписей выше), даже с "быстро" определение, оно замедляется ... ровно до 1,7 секунды. Это заставляет меня задуматься, возможно, исходная проблема связана с (отсутствием) логического вывода типа, даже если все должно быть правильно выведено.

Вот мои вопросы:

Откуда идет замедление?Почему сочинять сforce помочь, но используя строгийiterate Безразлично»т?ПочемуU.force хуже чемDeepSeq.force? Я понятия не имею чтоU.force должен делать, но это звучит очень похожеDeepSeq.forceи, похоже, имеет аналогичный эффект.Почему полиморфизм замедляет меняпорядок величины, не зависящий от того, где полиморфизм (т.е. в векторном типе, вNum типа или оба)?Почему версии 5 и 6, ни одна из которых не должна иметь никаких последствий для строгости, так же быстро, как строгая функция?

Как отметил @kqr, проблема неКажется, это строгость. Так что что-то о том, как я пишу функцию, вызывает общееzipWith для использования, а не для конкретной версии. Это просто случайность между GHC и векторной библиотекой, или здесь можно сказать что-то более общее?

Ответы на вопрос(1)

Ваш ответ на вопрос