Я не могу найти определение того, какие вызовы внутри выражения последовательности находятся в хвостовой позиции в F #, поэтому я настоятельно рекомендую не писать код, который зависит от семантики текущей реализации, т.е. это неопределенное поведение.
Например, попытка перечислить (например, применяя Seq.length
) следующую последовательность вызывает переполнение стека:
let rec xs() = seq { yield! xs() }
но, как отметил Томас, на самом деле работает следующее:
let rec xs n = seq { yield n; yield! xs(n+1) }
Мой совет - всегда заменять выражения рекурсивной последовательности на Seq.unfold
. В этом случае вы, вероятно, захотите накопить работу, которую нужно выполнить (например, когда вы вернетесь в левую ветвь, вы вставите правую ветвь в стек в аккумуляторе).
FWIW, даже справочник по языку F # ошибается. Он дает следующий код для выравнивания дерева:
type Tree<'a> =
| Tree of 'a * Tree<'a> * Tree<'a>
| Leaf of 'a
let rec inorder tree =
seq {
match tree with
| Tree(x, left, right) ->
yield! inorder left
yield x
yield! inorder right
| Leaf x -> yield x
}
Их собственный код убивает F # интерактивно с переполнением стека при подаче глубокого дерева слева.