2015-01-15 3 views
4

У меня есть выражение последовательности следующим образом:Переполнение стека и рекурсивная последовательность выражений F #

let fibSeq = 
    let rec fibSeq' a b = 
     seq { yield a 
       yield! fibSeq' b (a + b) } 
    fibSeq' 1 1 

Теперь даже для больших чисел, это не генерировать переполнение стека. Мне интересно, почему, мне кажется, что для генерации чисел Фибоначчи с этим выражением последовательности каждый рекурсивный вызов должен был вернуться обратно к вызывающему абоненту, чтобы в конечном итоге «свернуть» себя в последовательность. Здесь есть какая-то оптимизация?

+0

[Этот вопрос] (http://stackoverflow.com/questions/15864670/generate-tail-call-opcode), наряду с ответами на него, содержит довольно подробную информацию о генерации кода IL. – bytebuster

ответ

3

Да, это называется «хвост вызова оптимизации» Смотрите здесь: http://blogs.msdn.com/b/chrsmith/archive/2008/08/07/understanding-tail-recursion.aspx Также Seq ленив поэтому его пятисотый член не будет оцениваться до тех пор, пока не будет иметь доступа к ней в вашей программе, как:

let elm = Seq.nth 500 fibSeq 
+0

Я понимаю оптимизацию хвостовых вызовов, но для этого функция должна использовать хвостовую рекурсию, либо через накопитель, либо продолжение, и я не вижу, как это реализовано в данном случае. –

+0

Насколько я понимаю, рекурсивный вызов 'fibSeq'' находится в хвостовом положении, так как после этого вызова ничего в функции' fibSeq'' не выполняется. Чтобы процитировать сообщение выше: _ «Tail Recursion - это специализированный тип рекурсии, где есть гарантия, что в функции после выполнения рекурсивного вызова ничего не остается» _ – Christian

+3

Я не вижу, как в него входит оптимизация _tail. Глядя на декомпилятор, выражение последовательности скомпилируется в первоначальный вызов конструктору класса, генерируемого компилятором, который реализует абстрактный класс 'Microsoft.FSharp.Core.CompilerServices.GeneratedSequenceBase', и каждая итерация впоследствии строит новый экземпляр этого , А где же хвост? – kaefer

Смежные вопросы