[英]Is it possible to tail call optimize a grouping function in f# using sequences?
这是我的未优化尾调用的尝试,因为我需要配置枚举器:
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
我会很茫然。 我真的很希望能够使用通用序列来完成这项工作。
仅供参考,我知道此代码无法在当前状态下工作,因为我最终将多次处理枚举数。
您可以将try .. finally
块从内部some
函数(在每次迭代中输入的地方)移动到主要函数。 然后内部递归函数some
变为尾递归:
let Group func seed (items : seq<'t>) =
// The handling of exceptions is done by the caller,
// so 'some' does not need to handle exceptions...
let rec some (i : IEnumerator<'t>) state = seq {
if i.MoveNext()
then
let newstate, iscomplete = func (i.Current) state
if iscomplete then
yield newstate
// Recursive call in tail-call position
yield! some i newstate
else
yield state }
// Return a sequence that wraps the obtains the IEnumerator
// and guarantees that it gets disposed if 'some' fails
seq {
let i = items.GetEnumerator ()
try
// This is still not-tail recursive
yield! some i seed
finally
i.Dispose() }
甚至更好的是,您可以使用use
构造实现从Group
返回的序列:
seq {
use i = items.GetEnumerator ()
// This is still not-tail recursive
yield! some i seed }
实际上,我认为这比原始代码更正确,因为它仅调用一次Dispose
方法。 在您的版本中,每次执行进入some
执行时,它将被调用一次(这取决于异常发生之前处理的元素数量)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.