LINUX.ORG.RU

Haskell - оптимизация


0

0

Набралось уже несколько примеров кода, компилируемых/интерпретируемых по разному - к примеру hugs будет пытаться найти last [1..] итеративно практически не расходуя память, а ghc с любой оптимизацией или без нее - рекурсивно, съедая 1 гб памяти секунд за 5. Другой пример ghc переделывал в итерацию с -O0, но оставлял рекурсию с -O1 и -O2 (если надо могу выложить код).

Хотелось бы узнать, из каких соображений ghc оставляет рекурсию, и какие опции на это влияют (копание по документации успехом не окончилось), т.к. я подумываю, стоит ли реализовывать BSP деревья сложных моделей на нем.

★★

Попробывал скомпилить

main = print (last [(1::Int)..])

hug-ом и ghc -02

Память не жрет.

Насчет оптимизации хз, но канонически вычисление last[1..] должно выглядеть примерно как последовательность выражений вроде:

last (1:[2..])

last [2..]

last (2:[3..])

last [3..]

А весь лишний мусор собираться, как только будет достигнут некоторый лимит памяти (вряд ли hugs или ghc будет откладывать сборку мосора до момента, когда не будет забит весь своп)

Что такое BSP тоже хз, но вот например если есть дерево поиска, то выражение вида

del 1 (ins 1 (del 1 (ins 1 empty_tree))))

не будет вычисленно до тех пор пока не будет произведен поиск.

Лекарство от этого - либо seq, либо восклицательный знак при определении структуры:

data T a = T !Int !(T a) !(T a) | Empty

И тогда все поля будут полность вычисленны и утечек памяти не будет.

ival ★★
()

Где-то когда-то читал, что ему может придти в "голову" хранить этот самый [1..] - чтобы не вычислять второй раз. Что-то с этим делала опция no-cse. Если память мне не изменяет.

DonkeyHot ★★★★★
()
Ответ на: комментарий от ival

Проверил еще раз, версия ghc-6.4.2.20060309 - last [(1::Integer)..] ест 1 гб и убивается ядром, но! в hugs не ест больше 10М, с Int'ом ghc жрать перестал, хотя hugs и не начинал =)

P.S. BSP - огромные бинарные деревья для обсчета сцен, каждый узел это фэйс. Тут нужна производительность...

AiLr ★★
() автор топика
Ответ на: комментарий от DonkeyHot

Получается, что, во-первых, списки он не хранит, а во-вторых, я вообще ничего не понимаю =)
Пишем
main = do
print (last [(1::Integer)..100000000])
print (last [(1::Integer)..100000000])

Компилим с ghc -O2, запускаем - расход памяти 0.1%, время на вычисление первого и второго значений практически одинаково...

AiLr ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.