orangegoat's answer и Sec Oe's answer содержат ссылку, вероятно, лучшее место, чтобы узнать, как правильно написать последовательность Фибоначчи в Haskell, но вот некоторые не причин, почему ваш код неэффективен (обратите внимание, что ваш код не отличается от классического naive definition Элегантный Конечно Efficient Совершенство, нет.?.?):
Давайте рассмотрим, что происходит, когда вы звоните
fibonacci 5
Это расширяет в
(fibonacci 4) ++ [(last (fibonacci 4)) + (last (fibonacci 3))]
В дополнение к конкатенации двух списков вместе с ++
, мы уже можем видеть, что одно место, мы неэффективным в том, что мы вычислим fibonacci 4
дважды (два места мы назвали fibonacci (n-1)
. Но это становится хуже.
Везде говорит fibonacci 4
, что расширяется в
(fibonacci 3) ++ [(last (fibonacci 3)) + (last (fibonacci 2))]
И везде он говорит fibonacci 3
, что расширяется в
(fibonacci 2) ++ [(last (fibonacci 2)) + (last (fibonacci 1))]
Понятно, что это наивное определение имеет много повторных вычислений и это только ухудшается, когда n становится все больше и больше (скажем, 1000). fibonacci
не является списком, он просто возвращает списки, поэтому он не собирается волновать воспоминания о результатах предыдущих вычислений.
Кроме того, используя last
, вам необходимо перейти по списку, чтобы получить его последний элемент, который добавляет поверх проблем с этим рекурсивным определением (помните, что списки в Haskell не поддерживают постоянный случайный доступ во времени) они не являются динамическими массивами, это linked lists).
Один пример рекурсивного определения (из указанных ссылок), что делает держать вниз вычислений заключается в следующем:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Здесь fibs
на самом деле список, и мы можем принять преимущество ленивой оценки Хаскелла для генерации fibs
и tail fibs
по мере необходимости, в то время как предыдущие вычисления все еще хранятся внутри фиб.И, чтобы получить первые пять номеров, это так просто, как:
take 5 fibs -- [0,1,1,2,3]
(При желании можно заменить первую 0 с 1, если вы хотите, чтобы последовательность, чтобы начать с 1).
Если вы даже не можете найти время для поиска лучшего, то как вы можете найти время, чтобы узнать из ответа, представляющего лучший, и объяснить, почему это лучше? –
Возможно, дубликат: http://stackoverflow.com/questions/6562387/problem-with-fibonacci-haskell-implementation. В моем вопросе вопросы идентичны, так как этот пример имеет менее четкий пример кода. – HaskellElephant
@ThomasM.DuBuisson: Было полночь, и я спал, когда писал это. поэтому контекст должен был «не иметь времени прямо сейчас». Теперь я смотрю его и собираюсь irc .. –