@@ -108,6 +108,20 @@ namespace Microsoft.FSharp.Collections
108108 member __.GetHashCode o = c.GetHashCode o._ 1
109109 member __.Equals ( lhs , rhs ) = c.Equals ( lhs._ 1, rhs._ 1) }
110110
111+ [<AbstractClass>]
112+ type PreferGetEnumerator < 'T >() =
113+ inherit EnumerableBase< 'T>()
114+
115+ abstract GetEnumerator: unit -> IEnumerator < 'T >
116+ abstract GetSeq : unit -> ISeq < 'T >
117+
118+ interface IEnumerable< 'T> with
119+ member this.GetEnumerator () : IEnumerator < 'T > = this.GetEnumerator ()
120+
121+ interface ISeq< 'T> with
122+ member this.PushTransform < 'U > ( next : ITransformFactory < 'T , 'U >) : ISeq < 'U > = ( this.GetSeq()) .PushTransform next
123+ member this.Fold < 'Result > ( f : PipeIdx -> Folder < 'T , 'Result >) : 'Result = ( this.GetSeq()) .Fold f
124+
111125 [<CompiledName " Empty" >]
112126 let empty < 'T > = Microsoft.FSharp.Collections.SeqComposition.Core.EmptyEnumerable< 'T>. Instance
113127
@@ -592,17 +606,79 @@ namespace Microsoft.FSharp.Collections
592606 let concat ( sources : ISeq < #ISeq < 'T >>) : ISeq < 'T > =
593607 upcast ( ThinConcatEnumerable ( sources, id))
594608
609+ (*
610+ Represents the following seq comprehension, but they don't work at this level
611+
612+ seq {
613+ let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt folder
614+ let mutable state = initialState
615+ yield state
616+ for item in enumerable do
617+ state <- f.Invoke (state, item)
618+ yield state }
619+ *)
620+ type ScanEnumerator < 'T , 'State >( folder : 'State -> 'T -> 'State , initialState : 'State , enumerable :seq < 'T >) =
621+ let f = OptimizedClosures.FSharpFunc<_,_,_>. Adapt folder
622+
623+ let mutable state = 0 (* Pre-start*)
624+ let mutable enumerator = Unchecked.defaultof< IEnumerator< 'T>>
625+ let mutable current = initialState
626+
627+ interface IEnumerator< 'State> with
628+ member this.Current : 'State =
629+ match state with
630+ | 0 (* PreStart*) -> notStarted()
631+ | 1 (* GetEnumerator*) -> current
632+ | 2 (* MoveNext*) -> current
633+ | _ (* Finished*) -> alreadyFinished()
634+
635+ interface IEnumerator with
636+ member this.Current : obj =
637+ box ( this:> IEnumerator< 'State>) .Current
638+
639+ member this.MoveNext () : bool =
640+ match state with
641+ | 0 (* PreStart*) ->
642+ state <- 1 (* GetEnumerator*)
643+ true
644+ | 1 (* GetEnumerator*) ->
645+ enumerator <- enumerable.GetEnumerator ()
646+ state <- 2 (* MoveNext*)
647+ ( this:> IEnumerator) .MoveNext ()
648+ | 2 (* MoveNext*) ->
649+ if enumerator.MoveNext () then
650+ current <- f.Invoke ( current, enumerator.Current)
651+ true
652+ else
653+ current <- Unchecked.defaultof<_>
654+ state <- 3 (* Finished*)
655+ false
656+ | _ (* Finished*) -> alreadyFinished()
657+
658+ member this.Reset () : unit = noReset ()
659+
660+ interface IDisposable with
661+ member this.Dispose (): unit =
662+ if isNotNull enumerator then
663+ enumerator.Dispose ()
664+
595665 [<CompiledName " Scan" >]
596- let inline scan ( folder : 'State -> 'T -> 'State ) ( initialState : 'State ) ( source : ISeq < 'T >) : ISeq < 'State > =
597- let head = singleton initialState
598- let tail =
599- source.PushTransform { new ITransformFactory< 'T, 'State> with
600- override __.Compose _ _ next =
601- upcast { new Transform< 'T, 'V, 'State>( next, initialState) with
602- override this.ProcessNext ( input : 'T ) : bool =
603- this.State <- folder this.State input
604- TailCall.avoid ( next.ProcessNext this.State) } }
605- concat ( ofList [ head ; tail ])
666+ let scan ( folder : 'State -> 'T -> 'State ) ( initialState : 'State ) ( source : ISeq < 'T >) : ISeq < 'State > =
667+ upcast { new PreferGetEnumerator< 'State>() with
668+ member this.GetEnumerator () =
669+ upcast new ScanEnumerator< 'T, 'State>( folder, initialState, source)
670+
671+ member this.GetSeq () =
672+ let head = singleton initialState
673+ let tail =
674+ source.PushTransform { new ITransformFactory< 'T, 'State> with
675+ override __.Compose _ _ next =
676+ let f = OptimizedClosures.FSharpFunc<_,_,_>. Adapt folder
677+ upcast { new Transform< 'T, 'V, 'State>( next, initialState) with
678+ override this.ProcessNext ( input : 'T ) : bool =
679+ this.State <- f.Invoke ( this.State, input)
680+ TailCall.avoid ( next.ProcessNext this.State) } }
681+ concat ( ofList [ head ; tail ]) }
606682
607683 [<CompiledName " Skip" >]
608684 let skip ( skipCount : int ) ( source : ISeq < 'T >) : ISeq < 'T > =
0 commit comments