Насколько я знаю, !
(называемые bangs) используются, чтобы сигнализировать, что выражение должно строго оцениваться. Но для меня это не так очевидно, где их можно поставить или если вообще.
import qualified Data.Vector.Unboxed as V
main :: IO ()
main = print $ mean (V.enumFromTo 1 (10^9))
mean :: V.Vector Double -> Double
Различные версии среднего значения:
-- compiled with O2 ~ 1.14s
mean xs = acc / fromIntegral len
where !(len, acc) = V.foldl' f (0,0) xs :: (Int, Double)
f (len, acc) x = (len+1, acc+x)
-- compiled with O2 ~ 1.18s
mean xs = acc / fromIntegral len
where (!len, !acc) = V.foldl' f (0,0) xs :: (Int, Double)
f (len, acc) x = (len+1, acc+x)
-- compiled with O2 ~ 1.75s
mean xs = acc / fromIntegral len
where (len, acc) = V.foldl' f (0,0) xs :: (Int, Double)
f !(len, acc) x = (len+1, acc+x)
-- compiled with O2 ~ 1.75s
mean xs = acc / fromIntegral len
where (len, acc) = V.foldl' f (0,0) xs :: (Int, Double)
f (len, acc) x = (len+1, acc+x)
-- compiled without options ~ 6s
mean xs = acc / fromIntegral len
where (len, acc) = V.foldl' f (0,0) xs :: (Int, Double)
f (len, acc) x = (len+1, acc+x)
-- compiled without options ~ 12s
mean xs = acc / fromIntegral len
where !(len, acc) = V.foldl' f (0,0) xs :: (Int, Double)
f (len, acc) x = (len+1, acc+x)
Некоторые из них имеют смысл интуитивно, но я бы хотел, чтобы это было не просто методом проб и ошибок.
-
Есть ли способ обнаружить, когда ленивая оценка будет мешать производительности? Помимо тестирования каждый строго.
-
Разве это имеет смысл только для простых функций, таких как
mean
, где все нужно оценивать за один раз?