Во-первых, если вы выполняете сравнение производительности для числовых элементов, списки не являются лучшим выбором. Попробуйте пакет, такой как пакет vector для быстрых массивов.
Обратите внимание, что вы можете сделать еще лучше в Haskell благодаря слиянию с петлями. Записывая функцию create в качестве перечисления, компилятор может объединить шаг create и цикл fold в один цикл, который не выделяет промежуточных структур данных. Способность делать общий синтез, подобный этому, уникальна для GHC Haskell.
Я буду использовать векторную библиотеку (слитый цикл потока на основе):
import qualified Data.Vector as V
test = V.foldl (\ a b -> a + b * sqrt b) 0
create n = (V.enumFromTo 1 n)
main = print (test (create 1000000))
Теперь, перед тем, с кодом, компилятор не может удалить все списки, и мы в конечном итоге с внутренним цикл, как:
$wlgo :: Double# -> [Double] -> Double#
$wlgo =
\ (ww_sww :: Double#) (w_swy :: [Double]) ->
case w_swy of _ {
[] -> ww_sww;
: x_aoY xs_aoZ ->
case x_aoY of _ { D# x1_aql ->
$wlgo
(+##
ww_sww (*## x1_aql (sqrtDouble# x1_aql)))
xs_aoZ
}
}
$wcreate :: Double# -> [Double]
$wcreate =
\ (ww_swp :: Double#) ->
case ==## ww_swp 0.0 of _ {
False ->
:
@ Double
(D# ww_swp)
($wcreate (-## ww_swp 1.0));
True -> [] @ Double
}
Обратите внимания, как есть две петель: создание генераторных (отложенный) список, и складка потребляющей его. Благодаря лени, стоимость этого списка является дешевой, поэтому он работает в респектабельном:
$ time ./C
4.000004999999896e14
./C 0.06s user 0.00s system 98% cpu 0.058 total
При слиянии, однако, мы получаем вместо одного цикла только!
main_$s$wfoldlM_loop :: Double# -> Double# -> Double#
main_$s$wfoldlM_loop =
\ (sc_sYc :: Double#) (sc1_sYd :: Double#) ->
case <=## sc_sYc 1000000.5 of _ {
False -> sc1_sYd;
True ->
main_$s$wfoldlM_loop
(+## sc_sYc 1.0)
(+##
sc1_sYd (*## sc_sYc (sqrtDouble# sc_sYc)))
GHC сократил наши шаги по созданию и тестированию в один цикл без использования списков. Всего 2 рекорда в регистрах. И с половиной, как много циклов, он работает почти в два раза быстрее:
$ ghc D.hs -Odph -fvia-C -optc-O3 -optc-march=native -fexcess-precision --make
$ time ./D
4.000005000001039e14
./D 0.04s user 0.00s system 95% cpu 0.038 total
Это хороший пример силы, что гарантии чистоты обеспечивают - компилятор может быть очень агрессивен Reording кода.
OCaml имеет '' lazy' и Lazy.force'. Раньше это была очевидная реализация ML-стороны, которую любой мог написать со ссылкой на закрытие. Специальная поддержка была интегрирована во время выполнения в версии 3.0? и больше поддержки (сопоставление образцов) в 3.11.0. В настоящее время GC удаляет косвенные действия через некоторое время после принудительной приостановки. http://ralyx.inria.fr/2008/Raweb/gallium/uid48.html –