@@ -291,6 +291,27 @@ type AsyncSeqOp<'T> () =
291291[<AutoOpen>]
292292module AsyncSeqOp =
293293
294+ // Optimized enumerator for unfoldAsync with reduced allocations
295+ [<Sealed>]
296+ type OptimizedUnfoldEnumerator < 'S , 'T > ( f : 'S -> Async <( 'T * 'S ) option >, init : 'S ) =
297+ let mutable currentState = init
298+ let mutable disposed = false
299+
300+ interface IAsyncEnumerator< 'T> with
301+ member __.MoveNext () : Async < 'T option > =
302+ if disposed then async.Return None
303+ else async {
304+ let! result = f currentState
305+ match result with
306+ | None ->
307+ return None
308+ | Some ( value, nextState) ->
309+ currentState <- nextState
310+ return Some value
311+ }
312+ member __.Dispose () =
313+ disposed <- true
314+
294315 type UnfoldAsyncEnumerator < 'S , 'T > ( f : 'S -> Async <( 'T * 'S ) option >, init : 'S ) =
295316 inherit AsyncSeqOp< 'T> ()
296317 override x.IterAsync g = async {
@@ -337,17 +358,7 @@ module AsyncSeqOp =
337358 new UnfoldAsyncEnumerator< 'S, 'U> ( h, init) :> _
338359 interface IAsyncEnumerable< 'T> with
339360 member __.GetEnumerator () =
340- let s = ref init
341- { new IAsyncEnumerator< 'T> with
342- member __.MoveNext () : Async < 'T option > = async {
343- let! next = f ! s
344- match next with
345- | None ->
346- return None
347- | Some ( a, s') ->
348- s := s'
349- return Some a }
350- member __.Dispose () = () }
361+ new OptimizedUnfoldEnumerator< 'S, 'T>( f, init) :> IAsyncEnumerator< 'T>
351362
352363
353364
@@ -784,14 +795,32 @@ module AsyncSeq =
784795 // --------------------------------------------------------------------------
785796 // Additional combinators (implemented as async/asyncSeq computations)
786797
798+ // Optimized mapAsync enumerator that avoids computation builder overhead
799+ type private OptimizedMapAsyncEnumerator < 'T , 'TResult >( source : IAsyncEnumerator < 'T >, f : 'T -> Async < 'TResult >) =
800+ let mutable disposed = false
801+
802+ interface IAsyncEnumerator< 'TResult> with
803+ member _.MoveNext () = async {
804+ let! moveResult = source.MoveNext()
805+ match moveResult with
806+ | None -> return None
807+ | Some value ->
808+ let! mapped = f value
809+ return Some mapped
810+ }
811+
812+ member _.Dispose () =
813+ if not disposed then
814+ disposed <- true
815+ source.Dispose()
816+
787817 let mapAsync f ( source : AsyncSeq < 'T >) : AsyncSeq < 'TResult > =
788818 match source with
789819 | :? AsyncSeqOp< 'T> as source -> source.MapAsync f
790820 | _ ->
791- asyncSeq {
792- for itm in source do
793- let! v = f itm
794- yield v }
821+ { new IAsyncEnumerable< 'TResult> with
822+ member _.GetEnumerator () =
823+ new OptimizedMapAsyncEnumerator< 'T, 'TResult>( source.GetEnumerator(), f) :> IAsyncEnumerator < 'TResult > }
795824
796825 let mapiAsync f ( source : AsyncSeq < 'T >) : AsyncSeq < 'TResult > = asyncSeq {
797826 let i = ref 0 L
0 commit comments