Вот моя попытка, которая не является хвост вызов оптимизирован, потому что мне нужно утилизировать перечислителем:Можно ли использовать функцию tail для оптимизации функции группировки в f # с использованием последовательностей?
let Group func seed (items : seq<'t>) =
let rec some (i : IEnumerator<'t>) state = seq {
try
if i.MoveNext()
then
let newstate, iscomplete = func (i.Current) state
if iscomplete
then
yield newstate
yield! some i newstate
else
yield state
finally
i.Dispose() }
some (items.GetEnumerator()) seed
А вот пример использования:
let buffer maxBufferSize items =
Group (fun item state ->
let newstate = [ item ] |> List.append state
if newstate.Length >= maxBufferSize
then (newstate, true)
else (newstate, false)) List.empty items
Если я могу избежать использования нумератор (т.е. Seq.head AND Seq.tail
) Я мог бы заставить его работать, но без Seq.tail
Я в затруднении. Я действительно надеюсь сделать эту работу с родовыми последовательностями.
И FYI Я знаю, что этот код не будет работать в текущем состоянии, потому что я в конечном итоге удалю перечислитель несколько раз.
Это была моя первая реализация, но я думал, что буду удален, когда она выйдет из сферы действия, и я подумал, что после выхода будет выходить за рамки !. Поскольку последовательность была ленивой, тогда перечислитель оказался бы расположенным до того, как последовательность будет перечислить ... Я сошел с ума? – Brad
@Brad Трюк заключается в использовании ключевого слова 'use' _inside_ блока' seq {..} '. Затем компилятор F # генерирует код, который распределяет ресурс после перечисления всей последовательности. Это было бы проблемой только в том случае, если 'use' находился внутри тела' Group', но не внутри 'seq {..}', который позже вызывает 'some', используя' yield! '. Надеюсь, это имеет смысл! –