diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs
index 10c4389cb95..932a849aa54 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs
@@ -181,6 +181,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom
Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]()
Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString()
Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx()
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a])
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3
+Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]
+Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core
+Microsoft.FSharp.Collections.ComposerModule: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule: System.Type GetType()
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object)
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty
@@ -404,6 +461,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core.
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2])
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T])
+Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
index c452c3f31c4..46020db9e40 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
@@ -194,6 +194,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom
Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]()
Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString()
Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx()
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a])
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3
+Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]
+Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core
+Microsoft.FSharp.Collections.ComposerModule: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule: System.Type GetType()
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object)
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty
@@ -419,6 +476,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core.
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2])
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T])
+Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs
index 8e5337ef4a8..0464eb1580f 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs
@@ -181,6 +181,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom
Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]()
Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString()
Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx()
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a])
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3
+Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]
+Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core
+Microsoft.FSharp.Collections.ComposerModule: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule: System.Type GetType()
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object)
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty
@@ -406,6 +463,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core.
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2])
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T])
+Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
index 531eebf0e8f..15ceb66e7d8 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
@@ -178,6 +178,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom
Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]()
Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString()
Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx()
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a])
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3
+Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]
+Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core
+Microsoft.FSharp.Collections.ComposerModule: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule: System.Type GetType()
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object)
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty
@@ -403,6 +460,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core.
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2])
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T])
+Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
index 7d320ad8483..8e71c1daaee 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
@@ -194,6 +194,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom
Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]()
Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString()
Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx()
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a])
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3
+Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]
+Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core
+Microsoft.FSharp.Collections.ComposerModule: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule: System.Type GetType()
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object)
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty
@@ -419,6 +476,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core.
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2])
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T])
+Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
index f731fcdbcc0..c5601ff12ef 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
@@ -181,6 +181,63 @@ Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.ICom
Microsoft.FSharp.Collections.ComparisonIdentity: System.Collections.Generic.IComparer`1[T] Structural[T]()
Microsoft.FSharp.Collections.ComparisonIdentity: System.String ToString()
Microsoft.FSharp.Collections.ComparisonIdentity: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void .ctor()
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Boolean ProcessNext(T)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: TResult Value
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void .ctor(TResult)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnComplete(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining: Void OnDispose()
+Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand: Void StopFurtherProcessing(Int32)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Consumer`2 Create[V](IOutOfBand, System.Nullable`1[System.Int32], Consumer`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 PipeIdx
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]: Int32 get_PipeIdx()
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: ISeq`1 Compose[TResult](ISeqFactory`2)
+Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]: a ForEach[a](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit],a])
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: Void .ctor(a, b)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: Void .ctor(a, b, c)
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: a _1
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: b _2
+Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]: c _3
+Microsoft.FSharp.Collections.ComposerModule+Core: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule+Core: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Consumer`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Folder`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ICompletionChaining
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+IOutOfBand
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeqFactory`2[T,TResult]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+ISeq`1[T]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`2[a,b]
+Microsoft.FSharp.Collections.ComposerModule+Core: Microsoft.FSharp.Collections.ComposerModule+Core+Values`3[a,b,c]
+Microsoft.FSharp.Collections.ComposerModule+Core: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule+Core: System.Type GetType()
+Microsoft.FSharp.Collections.ComposerModule: Boolean Equals(System.Object)
+Microsoft.FSharp.Collections.ComposerModule: Int32 GetHashCode()
+Microsoft.FSharp.Collections.ComposerModule: Microsoft.FSharp.Collections.ComposerModule+Core
+Microsoft.FSharp.Collections.ComposerModule: System.String ToString()
+Microsoft.FSharp.Collections.ComposerModule: System.Type GetType()
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Boolean Equals(System.Object)
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Cons
Microsoft.FSharp.Collections.FSharpList`1+Tags[T]: Int32 Empty
@@ -406,6 +463,7 @@ Microsoft.FSharp.Collections.SeqModule: Boolean Exists[T](Microsoft.FSharp.Core.
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll2[T1,T2](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,System.Boolean]], System.Collections.Generic.IEnumerable`1[T1], System.Collections.Generic.IEnumerable`1[T2])
Microsoft.FSharp.Collections.SeqModule: Boolean ForAll[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Boolean IsEmpty[T](System.Collections.Generic.IEnumerable`1[T])
+Microsoft.FSharp.Collections.SeqModule: ISeq`1 ToComposer[T](System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 CompareWith[T](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[T,System.Int32]], System.Collections.Generic.IEnumerable`1[T], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndexBack[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
Microsoft.FSharp.Collections.SeqModule: Int32 FindIndex[T](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], System.Collections.Generic.IEnumerable`1[T])
diff --git a/src/fsharp/FSharp.Core/FSharp.Core.fsproj b/src/fsharp/FSharp.Core/FSharp.Core.fsproj
index 1909f2ddfb6..861202ebf44 100644
--- a/src/fsharp/FSharp.Core/FSharp.Core.fsproj
+++ b/src/fsharp/FSharp.Core/FSharp.Core.fsproj
@@ -86,6 +86,18 @@
Collections/collections.fs
+
+
+ Collections/seqcore.fsi
+
+
+ Collections/seqcore.fs
+
+
+ Collections/seqcomposer.fsi
+
+
+ Collections/seqcomposer.fs
Collections/seq.fsi
diff --git a/src/fsharp/FSharp.Core/seq.fs b/src/fsharp/FSharp.Core/seq.fs
index d2cfe54622e..8aba11bd9ac 100644
--- a/src/fsharp/FSharp.Core/seq.fs
+++ b/src/fsharp/FSharp.Core/seq.fs
@@ -1,819 +1,5 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-namespace Microsoft.FSharp.Collections
- #nowarn "52" // The value has been copied to ensure the original is not mutated by this operation
-
- open System
- open System.Diagnostics
- open System.Collections
- open System.Collections.Generic
- open Microsoft.FSharp.Core
- open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
- open Microsoft.FSharp.Core.Operators
- open Microsoft.FSharp.Control
- open Microsoft.FSharp.Collections
-
- module IEnumerator =
-
-
- let noReset() = raise (new System.NotSupportedException(SR.GetString(SR.resetNotSupported)))
- let notStarted() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationNotStarted)))
- let alreadyFinished() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationAlreadyFinished)))
- let check started = if not started then notStarted()
- let dispose (r : System.IDisposable) = r.Dispose()
-
- let cast (e : IEnumerator) : IEnumerator<'T> =
- { new IEnumerator<'T> with
- member x.Current = unbox<'T> e.Current
- interface IEnumerator with
- member x.Current = unbox<'T> e.Current :> obj
- member x.MoveNext() = e.MoveNext()
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() =
- match e with
- | :? System.IDisposable as e -> e.Dispose()
- | _ -> () }
-
- /// A concrete implementation of an enumerator that returns no values
- []
- type EmptyEnumerator<'T>() =
- let mutable started = false
- interface IEnumerator<'T> with
- member x.Current =
- check started
- (alreadyFinished() : 'T)
-
- interface System.Collections.IEnumerator with
- member x.Current =
- check started
- (alreadyFinished() : obj)
- member x.MoveNext() =
- if not started then started <- true
- false
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() = ()
-
- let Empty<'T> () = (new EmptyEnumerator<'T>() :> IEnumerator<'T>)
-
- let rec tryItem index (e : IEnumerator<'T>) =
- if not (e.MoveNext()) then None
- elif index = 0 then Some(e.Current)
- else tryItem (index-1) e
-
- let rec nth index (e : IEnumerator<'T>) =
- if not (e.MoveNext()) then
- let shortBy = index + 1
- invalidArgFmt "index"
- "{0}\nseq was short by {1} {2}"
- [|SR.GetString SR.notEnoughElements; shortBy; (if shortBy = 1 then "element" else "elements")|]
- if index = 0 then e.Current
- else nth (index-1) e
-
- []
- type MapEnumeratorState =
- | NotStarted
- | InProcess
- | Finished
-
- []
- type MapEnumerator<'T> () =
- let mutable state = NotStarted
- []
- val mutable private curr : 'T
-
- member this.GetCurrent () =
- match state with
- | NotStarted -> notStarted()
- | Finished -> alreadyFinished()
- | InProcess -> ()
- this.curr
-
- abstract DoMoveNext : byref<'T> -> bool
- abstract Dispose : unit -> unit
-
- interface IEnumerator<'T> with
- member this.Current = this.GetCurrent()
-
- interface IEnumerator with
- member this.Current = box(this.GetCurrent())
- member this.MoveNext () =
- state <- InProcess
- if this.DoMoveNext(&this.curr) then
- true
- else
- state <- Finished
- false
- member this.Reset() = noReset()
- interface System.IDisposable with
- member this.Dispose() = this.Dispose()
-
- let map f (e : IEnumerator<_>) : IEnumerator<_>=
- upcast
- { new MapEnumerator<_>() with
- member this.DoMoveNext (curr : byref<_>) =
- if e.MoveNext() then
- curr <- (f e.Current)
- true
- else
- false
- member this.Dispose() = e.Dispose()
- }
-
- let mapi f (e : IEnumerator<_>) : IEnumerator<_> =
- let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
- let i = ref (-1)
- upcast
- { new MapEnumerator<_>() with
- member this.DoMoveNext curr =
- i := !i + 1
- if e.MoveNext() then
- curr <- f.Invoke(!i, e.Current)
- true
- else
- false
- member this.Dispose() = e.Dispose()
- }
-
- let map2 f (e1 : IEnumerator<_>) (e2 : IEnumerator<_>) : IEnumerator<_>=
- let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
- upcast
- { new MapEnumerator<_>() with
- member this.DoMoveNext curr =
- let n1 = e1.MoveNext()
- let n2 = e2.MoveNext()
- if n1 && n2 then
- curr <- f.Invoke(e1.Current, e2.Current)
- true
- else
- false
- member this.Dispose() =
- try
- e1.Dispose()
- finally
- e2.Dispose()
- }
-
- let mapi2 f (e1 : IEnumerator<_>) (e2 : IEnumerator<_>) : IEnumerator<_> =
- let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f)
- let i = ref (-1)
- upcast
- { new MapEnumerator<_>() with
- member this.DoMoveNext curr =
- i := !i + 1
- if (e1.MoveNext() && e2.MoveNext()) then
- curr <- f.Invoke(!i, e1.Current, e2.Current)
- true
- else
- false
- member this.Dispose() =
- try
- e1.Dispose()
- finally
- e2.Dispose()
- }
-
- let map3 f (e1 : IEnumerator<_>) (e2 : IEnumerator<_>) (e3 : IEnumerator<_>) : IEnumerator<_> =
- let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f)
- upcast
- { new MapEnumerator<_>() with
- member this.DoMoveNext curr =
- let n1 = e1.MoveNext()
- let n2 = e2.MoveNext()
- let n3 = e3.MoveNext()
-
- if n1 && n2 && n3 then
- curr <- f.Invoke(e1.Current, e2.Current, e3.Current)
- true
- else
- false
- member this.Dispose() =
- try
- e1.Dispose()
- finally
- try
- e2.Dispose()
- finally
- e3.Dispose()
- }
-
- let choose f (e : IEnumerator<'T>) =
- let started = ref false
- let curr = ref None
- let get() = check !started; (match !curr with None -> alreadyFinished() | Some x -> x)
- { new IEnumerator<'U> with
- member x.Current = get()
- interface IEnumerator with
- member x.Current = box (get())
- member x.MoveNext() =
- if not !started then started := true
- curr := None
- while ((!curr).IsNone && e.MoveNext()) do
- curr := f e.Current
- Option.isSome !curr
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() = e.Dispose() }
-
- let filter f (e : IEnumerator<'T>) =
- let started = ref false
- let this =
- { new IEnumerator<'T> with
- member x.Current = check !started; e.Current
- interface IEnumerator with
- member x.Current = check !started; box e.Current
- member x.MoveNext() =
- let rec next() =
- if not !started then started := true
- e.MoveNext() && (f e.Current || next())
- next()
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() = e.Dispose() }
- this
-
- let unfold f x : IEnumerator<_> =
- let state = ref x
- upcast
- { new MapEnumerator<_>() with
- member this.DoMoveNext curr =
- match f !state with
- | None -> false
- | Some(r,s) ->
- curr <- r
- state := s
- true
- member this.Dispose() = ()
- }
-
- let upto lastOption f =
- match lastOption with
- | Some b when b<0 -> Empty() // a request for -ve length returns empty sequence
- | _ ->
- let unstarted = -1 // index value means unstarted (and no valid index)
- let completed = -2 // index value means completed (and no valid index)
- let unreachable = -3 // index is unreachable from 0,1,2,3,...
- let finalIndex = match lastOption with
- | Some b -> b // here b>=0, a valid end value.
- | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type.
- // The Current value for a valid index is "f i".
- // Lazy<_> values are used as caches, to store either the result or an exception if thrown.
- // These "Lazy<_>" caches are created only on the first call to current and forced immediately.
- // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC.
- // For example, the full enumeration of Seq.initInfinite in the tests.
- // state
- let index = ref unstarted
- // a Lazy node to cache the result/exception
- let current = ref (Unchecked.defaultof<_>)
- let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand.
- let getCurrent() =
- if !index = unstarted then notStarted()
- if !index = completed then alreadyFinished()
- match box !current with
- | null -> current := Lazy<_>.Create(fun () -> f !index)
- | _ -> ()
- // forced or re-forced immediately.
- (!current).Force()
- { new IEnumerator<'U> with
- member x.Current = getCurrent()
- interface IEnumerator with
- member x.Current = box (getCurrent())
- member x.MoveNext() =
- if !index = completed then
- false
- elif !index = unstarted then
- setIndex 0
- true
- else (
- if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue))
- if !index = finalIndex then
- false
- else
- setIndex (!index + 1)
- true
- )
- member self.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() = () }
-
- let readAndClear r =
- lock r (fun () -> match !r with None -> None | Some _ as res -> r := None; res)
-
- let generateWhileSome openf compute closef : IEnumerator<'U> =
- let started = ref false
- let curr = ref None
- let state = ref (Some(openf()))
- let getCurr() =
- check !started
- match !curr with None -> alreadyFinished() | Some x -> x
- let start() = if not !started then (started := true)
-
- let dispose() = readAndClear state |> Option.iter closef
- let finish() = (try dispose() finally curr := None)
- { new IEnumerator<'U> with
- member x.Current = getCurr()
- interface IEnumerator with
- member x.Current = box (getCurr())
- member x.MoveNext() =
- start()
- match !state with
- | None -> false (* we started, then reached the end, then got another MoveNext *)
- | Some s ->
- match (try compute s with e -> finish(); reraise()) with
- | None -> finish(); false
- | Some _ as x -> curr := x; true
-
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() = dispose() }
-
- []
- type ArrayEnumerator<'T>(arr: 'T array) =
- let mutable curr = -1
- let mutable len = arr.Length
- member x.Get() =
- if curr >= 0 then
- if curr >= len then alreadyFinished()
- else arr.[curr]
- else
- notStarted()
- interface IEnumerator<'T> with
- member x.Current = x.Get()
- interface System.Collections.IEnumerator with
- member x.MoveNext() =
- if curr >= len then false
- else
- curr <- curr + 1
- (curr < len)
- member x.Current = box(x.Get())
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() = ()
-
- let ofArray arr = (new ArrayEnumerator<'T>(arr) :> IEnumerator<'T>)
-
- []
- type Singleton<'T>(v:'T) =
- let mutable started = false
- interface IEnumerator<'T> with
- member x.Current = v
- interface IEnumerator with
- member x.Current = box v
- member x.MoveNext() = if started then false else (started <- true; true)
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() = ()
-
- let Singleton x = (new Singleton<'T>(x) :> IEnumerator<'T>)
-
- let EnumerateThenFinally f (e : IEnumerator<'T>) =
- { new IEnumerator<'T> with
- member x.Current = e.Current
- interface IEnumerator with
- member x.Current = (e :> IEnumerator).Current
- member x.MoveNext() = e.MoveNext()
- member x.Reset() = noReset()
- interface System.IDisposable with
- member x.Dispose() =
- try
- e.Dispose()
- finally
- f()
- }
-
- // Use generators for some implementations of IEnumerables.
- //
- module Generator =
-
- open System.Collections
- open System.Collections.Generic
-
- []
- type Step<'T> =
- | Stop
- | Yield of 'T
- | Goto of Generator<'T>
-
- and Generator<'T> =
- abstract Apply: (unit -> Step<'T>)
- abstract Disposer: (unit -> unit) option
-
- let disposeG (g:Generator<'T>) =
- match g.Disposer with
- | None -> ()
- | Some f -> f()
-
- let appG (g:Generator<_>) =
- //System.Console.WriteLine("{0}.appG", box g)
- let res = g.Apply()
- match res with
- | Goto(next) ->
- Goto(next)
- | Yield _ ->
- res
- | Stop ->
- //System.Console.WriteLine("appG: Stop")
- disposeG g
- res
-
- // Binding.
- //
- // We use a type definition to apply a local dynamic optimization.
- // We automatically right-associate binding, i.e. push the continuations to the right.
- // That is, bindG (bindG G1 cont1) cont2 --> bindG G1 (cont1 o cont2)
- // This makes constructs such as the following linear rather than quadratic:
- //
- // let rec rwalk n = { if n > 0 then
- // yield! rwalk (n-1)
- // yield n }
-
- type GenerateThen<'T>(g:Generator<'T>, cont : unit -> Generator<'T>) =
- member self.Generator = g
- member self.Cont = cont
- interface Generator<'T> with
- member x.Apply = (fun () ->
- match appG g with
- | Stop ->
- // OK, move onto the generator given by the continuation
- Goto(cont())
-
- | Yield _ as res ->
- res
-
- | Goto next ->
- Goto(GenerateThen<_>.Bind(next,cont)))
- member x.Disposer =
- g.Disposer
-
-
- static member Bind (g:Generator<'T>, cont) =
- match g with
- | :? GenerateThen<'T> as g -> GenerateThen<_>.Bind(g.Generator,(fun () -> GenerateThen<_>.Bind (g.Cont(), cont)))
- | g -> (new GenerateThen<'T>(g, cont) :> Generator<'T>)
-
-
- let bindG g cont = GenerateThen<_>.Bind(g,cont)
-
-
- // Internal type. Drive an underlying generator. Crucially when the generator returns
- // a new generator we simply update our current generator and continue. Thus the enumerator
- // effectively acts as a reference cell holding the current generator. This means that
- // infinite or large generation chains (e.g. caused by long sequences of append's, including
- // possible delay loops) can be referenced via a single enumerator.
- //
- // A classic case where this arises in this sort of sequence expression:
- // let rec data s = { yield s;
- // yield! data (s + random()) }
- //
- // This translates to
- // let rec data s = Seq.delay (fun () -> Seq.append (Seq.singleton s) (Seq.delay (fun () -> data (s+random()))))
- //
- // When you unwind through all the Seq, IEnumerator and Generator objects created,
- // you get (data s).GetEnumerator being an "GenerateFromEnumerator(EnumeratorWrappingLazyGenerator(...))" for the append.
- // After one element is yielded, we move on to the generator for the inner delay, which in turn
- // comes back to be a "GenerateFromEnumerator(EnumeratorWrappingLazyGenerator(...))".
- //
- // Defined as a type so we can optimize Enumerator/Generator chains in enumerateFromLazyGenerator
- // and GenerateFromEnumerator.
-
- []
- type EnumeratorWrappingLazyGenerator<'T>(g:Generator<'T>) =
- let mutable g = g
- let mutable curr = None
- let mutable finished = false
- member e.Generator = g
- interface IEnumerator<'T> with
- member x.Current= match curr with Some(v) -> v | None -> raise <| System.InvalidOperationException (SR.GetString(SR.moveNextNotCalledOrFinished))
- interface System.Collections.IEnumerator with
- member x.Current = box (x :> IEnumerator<_>).Current
- member x.MoveNext() =
- not finished &&
- (match appG g with
- | Stop ->
- curr <- None
- finished <- true
- false
- | Yield(v) ->
- curr <- Some(v)
- true
- | Goto(next) ->
- (g <- next)
- (x :> IEnumerator).MoveNext())
- member x.Reset() = IEnumerator.noReset()
- interface System.IDisposable with
- member x.Dispose() =
- if not finished then disposeG g
-
- // Internal type, used to optimize Enumerator/Generator chains
- type LazyGeneratorWrappingEnumerator<'T>(e:System.Collections.Generic.IEnumerator<'T>) =
- member g.Enumerator = e
- interface Generator<'T> with
- member g.Apply = (fun () ->
- if e.MoveNext() then
- Yield(e.Current)
- else
- Stop)
- member g.Disposer= Some(e.Dispose)
-
- let EnumerateFromGenerator(g:Generator<'T>) =
- match g with
- | :? LazyGeneratorWrappingEnumerator<'T> as g -> g.Enumerator
- | _ -> (new EnumeratorWrappingLazyGenerator<_>(g) :> System.Collections.Generic.IEnumerator<_>)
-
- let GenerateFromEnumerator (e:System.Collections.Generic.IEnumerator<'T>) =
- match e with
- | :? EnumeratorWrappingLazyGenerator<'T> as e -> e.Generator
- | _ -> (new LazyGeneratorWrappingEnumerator<'T>(e) :> Generator<'T>)
-
-namespace Microsoft.FSharp.Core.CompilerServices
-
- open System
- open System.Diagnostics
- open Microsoft.FSharp.Core
- open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
- open Microsoft.FSharp.Core.Operators
- open Microsoft.FSharp.Control
- open Microsoft.FSharp.Collections
- open Microsoft.FSharp.Primitives.Basics
- open System.Collections
- open System.Collections.Generic
-
- module RuntimeHelpers =
-
- []
- type internal StructBox<'T when 'T : equality>(value:'T) =
- member x.Value = value
- static member Comparer =
- let gcomparer = HashIdentity.Structural<'T>
- { new IEqualityComparer> with
- member __.GetHashCode(v) = gcomparer.GetHashCode(v.Value)
- member __.Equals(v1,v2) = gcomparer.Equals(v1.Value,v2.Value) }
-
- let inline checkNonNull argName arg =
- match box arg with
- | null -> nullArg argName
- | _ -> ()
-
- let mkSeq f =
- { new IEnumerable<'U> with
- member x.GetEnumerator() = f()
- interface IEnumerable with
- member x.GetEnumerator() = (f() :> IEnumerator) }
-
- []
- type EmptyEnumerable<'T> =
- | EmptyEnumerable
- interface IEnumerable<'T> with
- member x.GetEnumerator() = IEnumerator.Empty<'T>()
- interface IEnumerable with
- member x.GetEnumerator() = (IEnumerator.Empty<'T>() :> IEnumerator)
-
- let Generate openf compute closef =
- mkSeq (fun () -> IEnumerator.generateWhileSome openf compute closef)
-
- let GenerateUsing (openf : unit -> ('U :> System.IDisposable)) compute =
- Generate openf compute (fun (s:'U) -> s.Dispose())
-
- let EnumerateFromFunctions opener moveNext current =
- Generate
- opener
- (fun x -> if moveNext x then Some(current x) else None)
- (fun x -> match box(x) with :? System.IDisposable as id -> id.Dispose() | _ -> ())
-
- // A family of enumerators that can have additional 'finally' actions added to the enumerator through
- // the use of mutation. This is used to 'push' the disposal action for a 'use' into the next enumerator.
- // For example,
- // seq { use x = ...
- // while ... }
- // results in the 'while' loop giving an adjustable enumerator. This is then adjusted by adding the disposal action
- // from the 'use' into the enumerator. This means that we avoid constructing a two-deep enumerator chain in this
- // common case.
- type IFinallyEnumerator =
- abstract AppendFinallyAction : (unit -> unit) -> unit
-
- /// A concrete implementation of IEnumerable that adds the given compensation to the "Dispose" chain of any
- /// enumerators returned by the enumerable.
- []
- type FinallyEnumerable<'T>(compensation: unit -> unit, restf: unit -> seq<'T>) =
- interface IEnumerable<'T> with
- member x.GetEnumerator() =
- try
- let ie = restf().GetEnumerator()
- match ie with
- | :? IFinallyEnumerator as a ->
- a.AppendFinallyAction(compensation)
- ie
- | _ ->
- IEnumerator.EnumerateThenFinally compensation ie
- with e ->
- compensation()
- reraise()
- interface IEnumerable with
- member x.GetEnumerator() = ((x :> IEnumerable<'T>).GetEnumerator() :> IEnumerator)
-
- /// An optimized object for concatenating a sequence of enumerables
- []
- type ConcatEnumerator<'T,'U when 'U :> seq<'T>>(sources: seq<'U>) =
- let mutable outerEnum = sources.GetEnumerator()
- let mutable currInnerEnum = IEnumerator.Empty()
-
- let mutable started = false
- let mutable finished = false
- let mutable compensations = []
-
- [] // false = unchecked
- val mutable private currElement : 'T
-
- member x.Finish() =
- finished <- true
- try
- match currInnerEnum with
- | null -> ()
- | _ ->
- try
- currInnerEnum.Dispose()
- finally
- currInnerEnum <- null
- finally
- try
- match outerEnum with
- | null -> ()
- | _ ->
- try
- outerEnum.Dispose()
- finally
- outerEnum <- null
- finally
- let rec iter comps =
- match comps with
- | [] -> ()
- | h::t ->
- try h() finally iter t
- try
- compensations |> List.rev |> iter
- finally
- compensations <- []
-
- member x.GetCurrent() =
- IEnumerator.check started
- if finished then IEnumerator.alreadyFinished() else x.currElement
-
- interface IFinallyEnumerator with
- member x.AppendFinallyAction(f) =
- compensations <- f :: compensations
-
- interface IEnumerator<'T> with
- member x.Current = x.GetCurrent()
-
- interface IEnumerator with
- member x.Current = box (x.GetCurrent())
-
- member x.MoveNext() =
- if not started then (started <- true)
- if finished then false
- else
- let rec takeInner () =
- // check the inner list
- if currInnerEnum.MoveNext() then
- x.currElement <- currInnerEnum.Current
- true
- else
- // check the outer list
- let rec takeOuter() =
- if outerEnum.MoveNext() then
- let ie = outerEnum.Current
- // Optimization to detect the statically-allocated empty IEnumerables
- match box ie with
- | :? EmptyEnumerable<'T> ->
- // This one is empty, just skip, don't call GetEnumerator, try again
- takeOuter()
- | _ ->
- // OK, this one may not be empty.
- // Don't forget to dispose of the enumerator for the inner list now we're done with it
- currInnerEnum.Dispose()
- currInnerEnum <- ie.GetEnumerator()
- takeInner ()
- else
- // We're done
- x.Finish()
- false
- takeOuter()
- takeInner ()
-
- member x.Reset() = IEnumerator.noReset()
-
- interface System.IDisposable with
- member x.Dispose() =
- if not finished then
- x.Finish()
-
- let EnumerateUsing (resource : 'T :> System.IDisposable) (rest: 'T -> #seq<'U>) =
- (FinallyEnumerable((fun () -> match box resource with null -> () | _ -> resource.Dispose()),
- (fun () -> rest resource :> seq<_>)) :> seq<_>)
-
- let mkConcatSeq (sources: seq<'U :> seq<'T>>) =
- mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>)
-
- let EnumerateWhile (g : unit -> bool) (b: seq<'T>) : seq<'T> =
- let started = ref false
- let curr = ref None
- let getCurr() =
- IEnumerator.check !started
- match !curr with None -> IEnumerator.alreadyFinished() | Some x -> x
- let start() = if not !started then (started := true)
-
- let finish() = (curr := None)
- mkConcatSeq
- (mkSeq (fun () ->
- { new IEnumerator<_> with
- member x.Current = getCurr()
- interface IEnumerator with
- member x.Current = box (getCurr())
- member x.MoveNext() =
- start()
- let keepGoing = (try g() with e -> finish (); reraise ()) in
- if keepGoing then
- curr := Some(b); true
- else
- finish(); false
- member x.Reset() = IEnumerator.noReset()
- interface System.IDisposable with
- member x.Dispose() = () }))
-
- let EnumerateThenFinally (rest : seq<'T>) (compensation : unit -> unit) =
- (FinallyEnumerable(compensation, (fun () -> rest)) :> seq<_>)
-
- let CreateEvent (add : 'Delegate -> unit) (remove : 'Delegate -> unit) (create : (obj -> 'Args -> unit) -> 'Delegate ) :IEvent<'Delegate,'Args> =
- // Note, we implement each interface explicitly: this works around a bug in the CLR
- // implementation on CompactFramework 3.7, used on Windows Phone 7
- { new obj() with
- member x.ToString() = ""
- interface IEvent<'Delegate,'Args>
- interface IDelegateEvent<'Delegate> with
- member x.AddHandler(h) = add h
- member x.RemoveHandler(h) = remove h
- interface System.IObservable<'Args> with
- member x.Subscribe(r:IObserver<'Args>) =
- let h = create (fun _ args -> r.OnNext(args))
- add h
- { new System.IDisposable with
- member x.Dispose() = remove h } }
-
-
- []
- type GeneratedSequenceBase<'T>() =
- let mutable redirectTo : GeneratedSequenceBase<'T> = Unchecked.defaultof<_>
- let mutable redirect : bool = false
-
- abstract GetFreshEnumerator : unit -> IEnumerator<'T>
- abstract GenerateNext : next:byref> -> int // 0 = Stop, 1 = Yield, 2 = Goto
- abstract Close: unit -> unit
- abstract CheckClose: bool
- abstract LastGenerated : 'T
-
- //[]
- member x.MoveNextImpl() =
- let active =
- if redirect then redirectTo
- else x
- let mutable target = null
- match active.GenerateNext(&target) with
- | 1 ->
- true
- | 2 ->
- match target.GetEnumerator() with
- | :? GeneratedSequenceBase<'T> as g when not active.CheckClose ->
- redirectTo <- g
- | e ->
- redirectTo <-
- { new GeneratedSequenceBase<'T>() with
- member x.GetFreshEnumerator() = e
- member x.GenerateNext(_) = if e.MoveNext() then 1 else 0
- member x.Close() = try e.Dispose() finally active.Close()
- member x.CheckClose = true
- member x.LastGenerated = e.Current }
- redirect <- true
- x.MoveNextImpl()
- | _ (* 0 *) ->
- false
-
- interface IEnumerable<'T> with
- member x.GetEnumerator() = x.GetFreshEnumerator()
- interface IEnumerable with
- member x.GetEnumerator() = (x.GetFreshEnumerator() :> IEnumerator)
- interface IEnumerator<'T> with
- member x.Current = if redirect then redirectTo.LastGenerated else x.LastGenerated
- member x.Dispose() = if redirect then redirectTo.Close() else x.Close()
- interface IEnumerator with
- member x.Current = box (if redirect then redirectTo.LastGenerated else x.LastGenerated)
-
- //[]
- member x.MoveNext() = x.MoveNextImpl()
-
- member x.Reset() = raise <| new System.NotSupportedException()
-
-
namespace Microsoft.FSharp.Collections
open System
@@ -827,7 +13,15 @@ namespace Microsoft.FSharp.Collections
open Microsoft.FSharp.Core.CompilerServices
open Microsoft.FSharp.Control
open Microsoft.FSharp.Collections
+ open Microsoft.FSharp.Collections.Composer
+ open Microsoft.FSharp.Collections.Composer.Core
open Microsoft.FSharp.Primitives.Basics
+ open Microsoft.FSharp.Collections.IEnumerator
+
+ module Upcast =
+ // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality
+ // is fixed with the compiler then these functions can be removed.
+ let inline enumerable (t:#IEnumerable<'T>) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #)
[]
type CachedSeq<'T>(cleanup,res:seq<'T>) =
@@ -843,118 +37,103 @@ namespace Microsoft.FSharp.Collections
[]
[]
module Seq =
-
#if FX_NO_ICLONEABLE
open Microsoft.FSharp.Core.ICloneableExtensions
#else
#endif
-
- open Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers
-
let mkDelayedSeq (f: unit -> IEnumerable<'T>) = mkSeq (fun () -> f().GetEnumerator())
- let mkUnfoldSeq f x = mkSeq (fun () -> IEnumerator.unfold f x)
let inline indexNotFound() = raise (new System.Collections.Generic.KeyNotFoundException(SR.GetString(SR.keyNotFoundAlt)))
+ []
+ let toComposer (source:seq<'T>): Composer.Core.ISeq<'T> =
+ checkNonNull "source" source
+ Composer.ofSeq source
+
+ let toComposer' name (source:seq<'T>): Composer.Core.ISeq<'T> =
+ checkNonNull name source
+ Composer.ofSeq source
+
[]
let delay f = mkDelayedSeq f
[]
- let unfold f x = mkUnfoldSeq f x
+ let unfold (generator:'State->option<'T * 'State>) (state:'State) : seq<'T> =
+ Composer.unfold generator state
+ |> Upcast.enumerable
[]
let empty<'T> = (EmptyEnumerable :> seq<'T>)
[]
- let initInfinite f = mkSeq (fun () -> IEnumerator.upto None f)
+ let initInfinite<'T> (f:int->'T) : IEnumerable<'T> =
+ Composer.initInfinite f
+ |> Upcast.enumerable
[]
- let init count f =
- if count < 0 then invalidArgInputMustBeNonNegative "count" count
- mkSeq (fun () -> IEnumerator.upto (Some (count-1)) f)
+ let init<'T> (count:int) (f:int->'T) : IEnumerable<'T> =
+ Composer.init count f
+ |> Upcast.enumerable
[]
let iter f (source : seq<'T>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- while e.MoveNext() do
- f e.Current
+ source |> toComposer |> Composer.iter f
+
+ []
+ let tryHead (source : seq<_>) =
+ source |> toComposer |> Composer.tryHead
+
+ []
+ let skip count (source: seq<_>) =
+ source |> toComposer
+ |> Composer.skip count |> Upcast.enumerable
+
+ let invalidArgumnetIndex = invalidArgFmt "index"
[]
let item i (source : seq<'T>) =
- checkNonNull "source" source
- if i < 0 then invalidArgInputMustBeNonNegative "index" i
- use e = source.GetEnumerator()
- IEnumerator.nth i e
+ if i < 0 then invalidArgInputMustBeNonNegative "index" i else
+ source
+ |> toComposer |> Composer.skip i |> Upcast.enumerable
+ |> tryHead
+ |> function
+ | None -> invalidArgFmt "index" "{0}\nseq was short by 1 element" [|SR.GetString SR.notEnoughElements|]
+ | Some value -> value
[]
- let tryItem i (source : seq<'T>) =
- checkNonNull "source" source
- if i < 0 then None else
- use e = source.GetEnumerator()
- IEnumerator.tryItem i e
+ let tryItem i (source:seq<'T>) =
+ source |> toComposer |> Composer.tryItem i
- []
+ []
let nth i (source : seq<'T>) = item i source
- []
- let iteri f (source : seq<'T>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
- let mutable i = 0
- while e.MoveNext() do
- f.Invoke(i, e.Current)
- i <- i + 1
-
- []
- let exists f (source : seq<'T>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- let mutable state = false
- while (not state && e.MoveNext()) do
- state <- f e.Current
- state
+ []
+ let iteri f (source:seq<'T>) =
+ let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f
+ source |> toComposer |> Composer.iteri (fun idx a -> f.Invoke(idx,a))
- []
- let inline contains element (source : seq<'T>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- let mutable state = false
- while (not state && e.MoveNext()) do
- state <- element = e.Current
- state
+ []
+ let exists f (source:seq<'T>) =
+ source |> toComposer |> Composer.exists f
- []
- let forall f (source : seq<'T>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- let mutable state = true
- while (state && e.MoveNext()) do
- state <- f e.Current
- state
+ []
+ let inline contains element (source:seq<'T>) =
+ source |> toComposer |> Composer.contains element
+ []
+ let forall f (source:seq<'T>) =
+ source |> toComposer |> Composer.forall f
- []
- let iter2 f (source1 : seq<_>) (source2 : seq<_>) =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- use e1 = source1.GetEnumerator()
- use e2 = source2.GetEnumerator()
+ []
+ let iter2 (f:'T->'U->unit) (source1 : seq<'T>) (source2 : seq<'U>) =
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
- while (e1.MoveNext() && e2.MoveNext()) do
- f.Invoke(e1.Current, e2.Current)
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2")
+ ||> Composer.iter2 (fun a b -> f.Invoke(a,b))
- []
- let iteri2 f (source1 : seq<_>) (source2 : seq<_>) =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- use e1 = source1.GetEnumerator()
- use e2 = source2.GetEnumerator()
+ []
+ let iteri2 (f:int->'T->'U->unit) (source1 : seq<_>) (source2 : seq<_>) =
let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f)
- let mutable i = 0
- while (e1.MoveNext() && e2.MoveNext()) do
- f.Invoke(i, e1.Current, e2.Current)
- i <- i + 1
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2")
+ ||> Composer.iteri2 (fun idx a b -> f.Invoke(idx,a,b))
// Build an IEnumerble by wrapping/transforming iterators as they get generated.
let revamp f (ie : seq<_>) = mkSeq (fun () -> f (ie.GetEnumerator()))
@@ -964,63 +143,51 @@ namespace Microsoft.FSharp.Collections
mkSeq (fun () -> f (ie1.GetEnumerator()) (source2.GetEnumerator()) (source3.GetEnumerator()))
[]
- let filter f source =
- checkNonNull "source" source
- revamp (IEnumerator.filter f) source
+ let filter<'T> (f:'T->bool) (source:seq<'T>) : seq<'T> =
+ source |> toComposer |> Composer.filter f |> Upcast.enumerable
[]
- let where f source = filter f source
+ let where f source = filter f source
- []
- let map f source =
- checkNonNull "source" source
- revamp (IEnumerator.map f) source
+ []
+ let map<'T,'U> (f:'T->'U) (source:seq<'T>) : seq<'U> =
+ source |> toComposer |> Composer.map f |> Upcast.enumerable
- []
- let mapi f source =
- checkNonNull "source" source
- revamp (IEnumerator.mapi f) source
+ []
+ let mapi f source =
+ let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt f
+ source |> toComposer |> Composer.mapi (fun idx a ->f.Invoke(idx,a)) |> Upcast.enumerable
- []
- let mapi2 f source1 source2 =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- revamp2 (IEnumerator.mapi2 f) source1 source2
+ []
+ let mapi2 (mapfn:int->'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) =
+ let f = OptimizedClosures.FSharpFunc.Adapt mapfn
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2")
+ ||> Composer.mapi2 (fun idx a b ->f.Invoke(idx,a,b)) |> Upcast.enumerable
- []
- let map2 f source1 source2 =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- revamp2 (IEnumerator.map2 f) source1 source2
+ []
+ let map2<'T,'U,'V> (mapfn:'T->'U->'V) (source1:seq<'T>) (source2:seq<'U>) : seq<'V> =
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2")
+ ||> Composer.map2 mapfn |> Upcast.enumerable
- []
- let map3 f source1 source2 source3 =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- checkNonNull "source3" source3
- revamp3 (IEnumerator.map3 f) source1 source2 source3
+ []
+ let map3 mapfn source1 source2 source3 =
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2", source3 |> toComposer' "source3")
+ |||> Composer.map3 mapfn |> Upcast.enumerable
[]
- let choose f source =
- checkNonNull "source" source
- revamp (IEnumerator.choose f) source
+ let choose f source =
+ source |> toComposer |> Composer.choose f |> Upcast.enumerable
[]
let indexed source =
- checkNonNull "source" source
- mapi (fun i x -> i,x) source
+ source |> toComposer |> Composer.indexed |> Upcast.enumerable
[]
let zip source1 source2 =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
map2 (fun x y -> x,y) source1 source2
[]
let zip3 source1 source2 source3 =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- checkNonNull "source3" source3
map2 (fun x (y,z) -> x,y,z) source1 (zip source2 source3)
[]
@@ -1030,49 +197,30 @@ namespace Microsoft.FSharp.Collections
[]
let tryPick f (source : seq<'T>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- let mutable res = None
- while (Option.isNone res && e.MoveNext()) do
- res <- f e.Current
- res
+ source |> toComposer |> Composer.tryPick f
[]
let pick f source =
- checkNonNull "source" source
match tryPick f source with
| None -> indexNotFound()
| Some x -> x
[]
let tryFind f (source : seq<'T>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- let mutable res = None
- while (Option.isNone res && e.MoveNext()) do
- let c = e.Current
- if f c then res <- Some(c)
- res
+ source |> toComposer |> Composer.tryFind f
[]
let find f source =
- checkNonNull "source" source
match tryFind f source with
| None -> indexNotFound()
| Some x -> x
[]
let take count (source : seq<'T>) =
- checkNonNull "source" source
if count < 0 then invalidArgInputMustBeNonNegative "count" count
(* Note: don't create or dispose any IEnumerable if n = 0 *)
if count = 0 then empty else
- seq { use e = source.GetEnumerator()
- for x in 0 .. count - 1 do
- if not (e.MoveNext()) then
- invalidOpFmt "tried to take {0} {1} past the end of the seq"
- [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|]
- yield e.Current }
+ source |> toComposer |> Composer.take count |> Upcast.enumerable
[]
let isEmpty (source : seq<'T>) =
@@ -1085,11 +233,9 @@ namespace Microsoft.FSharp.Collections
use ie = source.GetEnumerator()
not (ie.MoveNext())
-
[]
- let concat sources =
- checkNonNull "sources" sources
- mkConcatSeq sources
+ let concat (sources:seq<#seq<'T>>) : seq<'T> =
+ sources |> toComposer' "sources" |> Composer.map toComposer |> Composer.concat |> Upcast.enumerable
[]
let length (source : seq<'T>) =
@@ -1105,78 +251,46 @@ namespace Microsoft.FSharp.Collections
state <- state + 1
state
- []
- let fold<'T,'State> f (x:'State) (source : seq<'T>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
+ []
+ let fold<'T,'State> (f:'State->'T->'State) (x:'State) (source:seq<'T>) =
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
- let mutable state = x
- while e.MoveNext() do
- state <- f.Invoke(state, e.Current)
- state
-
- []
- let fold2<'T1,'T2,'State> f (state:'State) (source1: seq<'T1>) (source2: seq<'T2>) =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
+ source |> toComposer
+ |> Composer.fold<'T,'State>(fun (a:'State) (b:'T) -> f.Invoke(a,b)) x
- use e1 = source1.GetEnumerator()
- use e2 = source2.GetEnumerator()
+ []
+ let fold2<'T1,'T2,'State> f (state:'State) (source1: seq<'T1>) (source2: seq<'T2>) =
let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f)
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2")
+ ||> Composer.fold2(fun s a b -> f.Invoke(s,a,b)) state
- let mutable state = state
- while e1.MoveNext() && e2.MoveNext() do
- state <- f.Invoke(state, e1.Current, e2.Current)
-
- state
-
- []
+ []
let reduce f (source : seq<'T>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if not (e.MoveNext()) then invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
- let mutable state = e.Current
- while e.MoveNext() do
- state <- f.Invoke(state, e.Current)
- state
-
- let fromGenerator f = mkSeq(fun () -> Generator.EnumerateFromGenerator (f()))
- let toGenerator (ie : seq<_>) = Generator.GenerateFromEnumerator (ie.GetEnumerator())
+ source |> toComposer |> Composer.reduce(fun a b -> f.Invoke(a,b))
[]
let replicate count x =
+ #if FX_ATLEAST_40
System.Linq.Enumerable.Repeat(x,count)
+ #else
+ if count < 0 then invalidArg "count" (SR.GetString(SR.inputMustBeNonNegative))
+ seq { for _ in 1 .. count -> x }
+ #endif
[]
let append (source1: seq<'T>) (source2: seq<'T>) =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- fromGenerator(fun () -> Generator.bindG (toGenerator source1) (fun () -> toGenerator source2))
-
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2")
+ ||> Composer.append |> Upcast.enumerable
[]
let collect f sources = map f sources |> concat
- []
+ []
let compareWith (f:'T -> 'T -> int) (source1 : seq<'T>) (source2: seq<'T>) =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- use e1 = source1.GetEnumerator()
- use e2 = source2.GetEnumerator()
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
- let rec go () =
- let e1ok = e1.MoveNext()
- let e2ok = e2.MoveNext()
- let c = if e1ok = e2ok then 0 else if e1ok then 1 else -1
- if c <> 0 then c else
- if not e1ok || not e2ok then 0
- else
- let c = f.Invoke(e1.Current, e2.Current)
- if c <> 0 then c else
- go ()
- go()
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2")
+ ||> Composer.compareWith (fun a b -> f.Invoke(a,b))
[]
let ofList (source : 'T list) =
@@ -1191,23 +305,11 @@ namespace Microsoft.FSharp.Collections
[]
let ofArray (source : 'T array) =
checkNonNull "source" source
- mkSeq (fun () -> IEnumerator.ofArray source)
+ Upcast.enumerable (Composer.ofArray source)
[]
let toArray (source : seq<'T>) =
- checkNonNull "source" source
- match source with
- | :? ('T[]) as res -> (res.Clone() :?> 'T[])
- | :? ('T list) as res -> List.toArray res
- | :? ICollection<'T> as res ->
- // Directly create an array and copy ourselves.
- // This avoids an extra copy if using ResizeArray in fallback below.
- let arr = Array.zeroCreateUnchecked res.Count
- res.CopyTo(arr, 0)
- arr
- | _ ->
- let res = ResizeArray<_>(source)
- res.ToArray()
+ source |> toComposer |> Composer.toArray
let foldArraySubRight (f:OptimizedClosures.FSharpFunc<'T,_,_>) (arr: 'T[]) start fin acc =
let mutable state = acc
@@ -1242,36 +344,18 @@ namespace Microsoft.FSharp.Collections
let singleton x = mkSeq (fun () -> IEnumerator.Singleton x)
- []
+ []
let truncate n (source: seq<'T>) =
- checkNonNull "source" source
- seq { let i = ref 0
- use ie = source.GetEnumerator()
- while !i < n && ie.MoveNext() do
- i := !i + 1
- yield ie.Current }
-
- []
- let pairwise (source: seq<'T>) =
- checkNonNull "source" source
- seq { use ie = source.GetEnumerator()
- if ie.MoveNext() then
- let iref = ref ie.Current
- while ie.MoveNext() do
- let j = ie.Current
- yield (!iref, j)
- iref := j }
-
- []
- let scan<'T,'State> f (z:'State) (source : seq<'T>) =
- checkNonNull "source" source
- let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
- seq { let zref = ref z
- yield !zref
- use ie = source.GetEnumerator()
- while ie.MoveNext() do
- zref := f.Invoke(!zref, ie.Current)
- yield !zref }
+ if n <= 0 then empty else
+ source |> toComposer |> Composer.truncate n |> Upcast.enumerable
+
+ []
+ let pairwise<'T> (source:seq<'T>) : seq<'T*'T> =
+ source |> toComposer |> Composer.pairwise |> Upcast.enumerable
+
+ []
+ let scan<'T,'State> (folder:'State->'T->'State) (state:'State) (source:seq<'T>) : seq<'State> =
+ source |> toComposer |> Composer.scan folder state |> Upcast.enumerable
[]
let tryFindBack f (source : seq<'T>) =
@@ -1291,31 +375,15 @@ namespace Microsoft.FSharp.Collections
let res = Array.scanSubRight f arr 0 (arr.Length - 1) acc
res :> seq<_>)
+ []
+ let tryFindIndex p (source:seq<_>) =
+ source |> toComposer |> Composer.tryFindIndex p
+
[]
let findIndex p (source:seq<_>) =
- checkNonNull "source" source
- use ie = source.GetEnumerator()
- let rec loop i =
- if ie.MoveNext() then
- if p ie.Current then
- i
- else loop (i+1)
- else
- indexNotFound()
- loop 0
-
- []
- let tryFindIndex p (source:seq<_>) =
- checkNonNull "source" source
- use ie = source.GetEnumerator()
- let rec loop i =
- if ie.MoveNext() then
- if p ie.Current then
- Some i
- else loop (i+1)
- else
- None
- loop 0
+ match tryFindIndex p source with
+ | None -> indexNotFound()
+ | Some x -> x
[]
let tryFindIndexBack f (source : seq<'T>) =
@@ -1330,27 +398,9 @@ namespace Microsoft.FSharp.Collections
// windowed : int -> seq<'T> -> seq<'T[]>
[]
let windowed windowSize (source: seq<_>) =
- checkNonNull "source" source
if windowSize <= 0 then invalidArgFmt "windowSize" "{0}\nwindowSize = {1}"
[|SR.GetString SR.inputMustBePositive; windowSize|]
- seq {
- let arr = Array.zeroCreateUnchecked windowSize
- let r = ref (windowSize - 1)
- let i = ref 0
- use e = source.GetEnumerator()
- while e.MoveNext() do
- arr.[!i] <- e.Current
- i := (!i + 1) % windowSize
- if !r = 0 then
- if windowSize < 32 then
- yield Array.init windowSize (fun j -> arr.[(!i+j) % windowSize])
- else
- let result = Array.zeroCreateUnchecked windowSize
- Array.Copy(arr, !i, result, 0, windowSize - !i)
- Array.Copy(arr, 0, result, windowSize - !i, !i)
- yield result
- else r := (!r - 1)
- }
+ source |> toComposer |> Composer.windowed windowSize |> Upcast.enumerable
[]
let cache (source : seq<'T>) =
@@ -1421,90 +471,40 @@ namespace Microsoft.FSharp.Collections
checkNonNull "source" source
mkSeq (fun () -> source.GetEnumerator())
- let inline groupByImpl (comparer:IEqualityComparer<'SafeKey>) (keyf:'T->'SafeKey) (getKey:'SafeKey->'Key) (seq:seq<'T>) =
- checkNonNull "seq" seq
-
- let dict = Dictionary<_,ResizeArray<_>> comparer
-
- // Previously this was 1, but I think this is rather stingy, considering that we are already paying
- // for at least a key, the ResizeArray reference, which includes an array reference, an Entry in the
- // Dictionary, plus any empty space in the Dictionary of unfilled hash buckets.
- let minimumBucketSize = 4
-
- // Build the groupings
- seq |> iter (fun v ->
- let safeKey = keyf v
- let mutable prev = Unchecked.defaultof<_>
- match dict.TryGetValue (safeKey, &prev) with
- | true -> prev.Add v
- | false ->
- let prev = ResizeArray ()
- dict.[safeKey] <- prev
- prev.Add v)
-
- // Trim the size of each result group, don't trim very small buckets, as excessive work, and garbage for
- // minimal gain
- dict |> iter (fun group -> if group.Value.Count > minimumBucketSize then group.Value.TrimExcess())
-
- // Return the sequence-of-sequences. Don't reveal the
- // internal collections: just reveal them as sequences
- dict |> map (fun group -> (getKey group.Key, readonly group.Value))
-
- // We avoid wrapping a StructBox, because under 64 JIT we get some "hard" tailcalls which affect performance
- let groupByValueType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl HashIdentity.Structural<'Key> keyf id
-
- // Wrap a StructBox around all keys in case the key type is itself a type using null as a representation
- let groupByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> groupByImpl StructBox<'Key>.Comparer (fun t -> StructBox (keyf t)) (fun sb -> sb.Value)
-
[]
- let groupBy (keyf:'T->'Key) (seq:seq<'T>) =
+ let groupBy (keyf:'T->'Key) (source:seq<'T>) =
+ let grouped =
#if FX_RESHAPED_REFLECTION
- if (typeof<'Key>).GetTypeInfo().IsValueType
+ if (typeof<'Key>).GetTypeInfo().IsValueType
#else
- if typeof<'Key>.IsValueType
+ if typeof<'Key>.IsValueType
#endif
- then mkDelayedSeq (fun () -> groupByValueType keyf seq)
- else mkDelayedSeq (fun () -> groupByRefType keyf seq)
+ then source |> toComposer |> Composer.GroupBy.byVal keyf
+ else source |> toComposer |> Composer.GroupBy.byRef keyf
+
+ grouped
+ |> Composer.map (fun (key,value) -> key, Upcast.enumerable value)
+ |> Upcast.enumerable
[]
let distinct source =
- checkNonNull "source" source
- seq { let hashSet = HashSet<'T>(HashIdentity.Structural<'T>)
- for v in source do
- if hashSet.Add(v) then
- yield v }
+ source |> toComposer |> Composer.distinct |> Upcast.enumerable
[]
let distinctBy keyf source =
- checkNonNull "source" source
- seq { let hashSet = HashSet<_>(HashIdentity.Structural<_>)
- for v in source do
- if hashSet.Add(keyf v) then
- yield v }
+ source |> toComposer |> Composer.distinctBy keyf |> Upcast.enumerable
[]
let sortBy keyf source =
- checkNonNull "source" source
- mkDelayedSeq (fun () ->
- let array = source |> toArray
- Array.stableSortInPlaceBy keyf array
- array :> seq<_>)
+ source |> toComposer |> Composer.sortBy keyf |> Upcast.enumerable
[]
let sort source =
- checkNonNull "source" source
- mkDelayedSeq (fun () ->
- let array = source |> toArray
- Array.stableSortInPlace array
- array :> seq<_>)
+ source |> toComposer |> Composer.sort |> Upcast.enumerable
[]
let sortWith f source =
- checkNonNull "source" source
- mkDelayedSeq (fun () ->
- let array = source |> toArray
- Array.stableSortInPlaceWith f array
- array :> seq<_>)
+ source |> toComposer |> Composer.sortWith f |> Upcast.enumerable
[]
let inline sortByDescending keyf source =
@@ -1518,303 +518,95 @@ namespace Microsoft.FSharp.Collections
let inline compareDescending a b = compare b a
sortWith compareDescending source
- let inline countByImpl (comparer:IEqualityComparer<'SafeKey>) (keyf:'T->'SafeKey) (getKey:'SafeKey->'Key) (source:seq<'T>) =
- checkNonNull "source" source
-
- let dict = Dictionary comparer
-
- // Build the groupings
- source |> iter (fun v ->
- let safeKey = keyf v
- let mutable prev = Unchecked.defaultof<_>
- if dict.TryGetValue(safeKey, &prev)
- then dict.[safeKey] <- prev + 1
- else dict.[safeKey] <- 1)
-
- dict |> map (fun group -> (getKey group.Key, group.Value))
-
- // We avoid wrapping a StructBox, because under 64 JIT we get some "hard" tailcalls which affect performance
- let countByValueType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl HashIdentity.Structural<'Key> keyf id
-
- // Wrap a StructBox around all keys in case the key type is itself a type using null as a representation
- let countByRefType (keyf:'T->'Key) (seq:seq<'T>) = seq |> countByImpl StructBox<'Key>.Comparer (fun t -> StructBox (keyf t)) (fun sb -> sb.Value)
-
[]
let countBy (keyf:'T->'Key) (source:seq<'T>) =
- checkNonNull "source" source
-
#if FX_RESHAPED_REFLECTION
if (typeof<'Key>).GetTypeInfo().IsValueType
#else
if typeof<'Key>.IsValueType
#endif
- then mkDelayedSeq (fun () -> countByValueType keyf source)
- else mkDelayedSeq (fun () -> countByRefType keyf source)
-
- []
- let inline sum (source: seq< ^a>) : ^a =
- use e = source.GetEnumerator()
- let mutable acc = LanguagePrimitives.GenericZero< ^a>
- while e.MoveNext() do
- acc <- Checked.(+) acc e.Current
- acc
-
- []
+ then source |> toComposer |> Composer.CountBy.byVal keyf |> Upcast.enumerable
+ else source |> toComposer |> Composer.CountBy.byRef keyf |> Upcast.enumerable
+
+ []
+ let inline sum (source:seq<'a>) : 'a =
+ source |> toComposer |> Composer.sum
+
+ []
let inline sumBy (f : 'T -> ^U) (source: seq<'T>) : ^U =
- use e = source.GetEnumerator()
- let mutable acc = LanguagePrimitives.GenericZero< ^U>
- while e.MoveNext() do
- acc <- Checked.(+) acc (f e.Current)
- acc
+ source |> toComposer |> Composer.sumBy f
- []
+ []
let inline average (source: seq< ^a>) : ^a =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- let mutable acc = LanguagePrimitives.GenericZero< ^a>
- let mutable count = 0
- while e.MoveNext() do
- acc <- Checked.(+) acc e.Current
- count <- count + 1
- if count = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
- LanguagePrimitives.DivideByInt< ^a> acc count
-
- []
+ source |> toComposer |> Composer.average
+
+ []
let inline averageBy (f : 'T -> ^U) (source: seq< 'T >) : ^U =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- let mutable acc = LanguagePrimitives.GenericZero< ^U>
- let mutable count = 0
- while e.MoveNext() do
- acc <- Checked.(+) acc (f e.Current)
- count <- count + 1
- if count = 0 then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
- LanguagePrimitives.DivideByInt< ^U> acc count
-
- []
- let inline min (source: seq<_>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if not (e.MoveNext()) then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
- let mutable acc = e.Current
- while e.MoveNext() do
- let curr = e.Current
- if curr < acc then
- acc <- curr
- acc
-
- []
- let inline minBy (f : 'T -> 'U) (source: seq<'T>) : 'T =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if not (e.MoveNext()) then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
- let first = e.Current
- let mutable acc = f first
- let mutable accv = first
- while e.MoveNext() do
- let currv = e.Current
- let curr = f currv
- if curr < acc then
- acc <- curr
- accv <- currv
- accv
-
-(*
- []
- let inline minValBy (f : 'T -> 'U) (source: seq<'T>) : 'U =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if not (e.MoveNext()) then
- invalidArg "source" InputSequenceEmptyString
- let first = e.Current
- let mutable acc = f first
- while e.MoveNext() do
- let currv = e.Current
- let curr = f currv
- if curr < acc then
- acc <- curr
- acc
-
-*)
- []
- let inline max (source: seq<_>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if not (e.MoveNext()) then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
- let mutable acc = e.Current
- while e.MoveNext() do
- let curr = e.Current
- if curr > acc then
- acc <- curr
- acc
-
- []
- let inline maxBy (f : 'T -> 'U) (source: seq<'T>) : 'T =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if not (e.MoveNext()) then
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
- let first = e.Current
- let mutable acc = f first
- let mutable accv = first
- while e.MoveNext() do
- let currv = e.Current
- let curr = f currv
- if curr > acc then
- acc <- curr
- accv <- currv
- accv
-
-
-(*
- []
- let inline maxValBy (f : 'T -> 'U) (source: seq<'T>) : 'U =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if not (e.MoveNext()) then
- invalidArg "source" InputSequenceEmptyString
- let first = e.Current
- let mutable acc = f first
- while e.MoveNext() do
- let currv = e.Current
- let curr = f currv
- if curr > acc then
- acc <- curr
- acc
-
-*)
- []
- let takeWhile p (source: seq<_>) =
- checkNonNull "source" source
- seq { use e = source.GetEnumerator()
- let latest = ref Unchecked.defaultof<_>
- while e.MoveNext() && (latest := e.Current; p !latest) do
- yield !latest }
+ source |> toComposer |> Composer.averageBy f
- []
- let skip count (source: seq<_>) =
- checkNonNull "source" source
- seq { use e = source.GetEnumerator()
- for x in 1 .. count do
- if not (e.MoveNext()) then
- invalidOpFmt "tried to skip {0} {1} past the end of the seq"
- [|SR.GetString SR.notEnoughElements; x; (if x=1 then "element" else "elements")|]
- while e.MoveNext() do
- yield e.Current }
+ []
+ let inline min (source: seq<'T>): 'T when 'T : comparison =
+ source |> toComposer |> Composer.min
- []
- let skipWhile p (source: seq<_>) =
- checkNonNull "source" source
- seq { use e = source.GetEnumerator()
- let latest = ref (Unchecked.defaultof<_>)
- let ok = ref false
- while e.MoveNext() do
- if (latest := e.Current; (!ok || not (p !latest))) then
- ok := true
- yield !latest }
+ []
+ let inline minBy (projection: 'T -> 'U when 'U:comparison) (source: seq<'T>) : 'T =
+ source |> toComposer |> Composer.minBy projection
+ []
+ let inline max (source: seq<'T>) =
+ source |> toComposer |> Composer.max
- []
- let forall2 p (source1: seq<_>) (source2: seq<_>) =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- use e1 = source1.GetEnumerator()
- use e2 = source2.GetEnumerator()
- let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p)
- let mutable ok = true
- while (ok && e1.MoveNext() && e2.MoveNext()) do
- ok <- p.Invoke(e1.Current, e2.Current)
- ok
+ []
+ let inline maxBy (projection: 'T -> 'U) (source: seq<'T>) : 'T =
+ source |> toComposer |> Composer.maxBy projection
+
+ []
+ let takeWhile predicate (source: seq<_>) =
+ source |> toComposer |> Composer.takeWhile predicate |> Upcast.enumerable
+ []
+ let skipWhile predicate (source: seq<_>) =
+ source |> toComposer |> Composer.skipWhile predicate |> Upcast.enumerable
- []
+ []
+ let forall2 p (source1: seq<_>) (source2: seq<_>) =
+ let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt p
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2")
+ ||> Composer.forall2 (fun a b -> p.Invoke(a,b))
+
+ []
let exists2 p (source1: seq<_>) (source2: seq<_>) =
- checkNonNull "source1" source1
- checkNonNull "source2" source2
- use e1 = source1.GetEnumerator()
- use e2 = source2.GetEnumerator()
- let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(p)
- let mutable ok = false
- while (not ok && e1.MoveNext() && e2.MoveNext()) do
- ok <- p.Invoke(e1.Current, e2.Current)
- ok
-
- []
- let head (source : seq<_>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if (e.MoveNext()) then e.Current
- else invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ let p = OptimizedClosures.FSharpFunc<_,_,_>.Adapt p
+ (source1 |> toComposer' "source1", source2 |> toComposer' "source2")
+ ||> Composer.exists2 (fun a b -> p.Invoke(a,b))
- []
- let tryHead (source : seq<_>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if (e.MoveNext()) then Some e.Current
- else None
+ []
+ let head (source : seq<_>) =
+ source |> toComposer |> Composer.head
- []
+ []
let tail (source: seq<'T>) =
- checkNonNull "source" source
- seq { use e = source.GetEnumerator()
- if not (e.MoveNext()) then
- invalidArg "source" (SR.GetString(SR.notEnoughElements))
- while e.MoveNext() do
- yield e.Current }
+ source |> toComposer |> Composer.tail |> Upcast.enumerable
+
+ []
+ let tryLast (source : seq<_>) =
+ source |> toComposer |> Composer.tryLast
[]
let last (source : seq<_>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if e.MoveNext() then
- let mutable res = e.Current
- while (e.MoveNext()) do res <- e.Current
- res
- else
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
-
- []
- let tryLast (source : seq<_>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if e.MoveNext() then
- let mutable res = e.Current
- while (e.MoveNext()) do res <- e.Current
- Some res
- else
- None
-
- []
+ source |> toComposer |> Composer.last
+
+ []
let exactlyOne (source : seq<_>) =
- checkNonNull "source" source
- use e = source.GetEnumerator()
- if e.MoveNext() then
- let v = e.Current
- if e.MoveNext() then
- invalidArg "source" (SR.GetString(SR.inputSequenceTooLong))
- else
- v
- else
- invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ source |> toComposer |> Composer.exactlyOne
[]
let rev source =
- checkNonNull "source" source
- mkDelayedSeq (fun () ->
- let array = source |> toArray
- Array.Reverse array
- array :> seq<_>)
+ source |> toComposer |> Composer.rev |> Upcast.enumerable
[]
- let permute f (source : seq<_>) =
- checkNonNull "source" source
- mkDelayedSeq (fun () ->
- source |> toArray |> Array.permute f :> seq<_>)
+ let permute f (source:seq<_>) =
+ source |> toComposer |> Composer.permute f |> Upcast.enumerable
[]
let mapFold<'T,'State,'Result> (f: 'State -> 'T -> 'Result * 'State) acc source =
@@ -1829,20 +621,10 @@ namespace Microsoft.FSharp.Collections
let arr,state = Array.mapFoldBack f array acc
readonly arr, state
- []
+ []
let except (itemsToExclude: seq<'T>) (source: seq<'T>) =
- checkNonNull "itemsToExclude" itemsToExclude
- checkNonNull "source" source
-
- seq {
- use e = source.GetEnumerator()
- if e.MoveNext() then
- let cached = HashSet(itemsToExclude, HashIdentity.Structural)
- let next = e.Current
- if (cached.Add next) then yield next
- while e.MoveNext() do
- let next = e.Current
- if (cached.Add next) then yield next }
+ if isEmpty itemsToExclude then source else
+ source |> toComposer |> Composer.except itemsToExclude |> Upcast.enumerable
[]
let chunkBySize chunkSize (source : seq<_>) =
diff --git a/src/fsharp/FSharp.Core/seq.fsi b/src/fsharp/FSharp.Core/seq.fsi
index f05e9db76dd..76ca68bb866 100644
--- a/src/fsharp/FSharp.Core/seq.fsi
+++ b/src/fsharp/FSharp.Core/seq.fsi
@@ -7,13 +7,12 @@ namespace Microsoft.FSharp.Collections
open System.Collections.Generic
open Microsoft.FSharp.Core
open Microsoft.FSharp.Collections
-
+
/// Basic operations on IEnumerables.
[]
[]
- module Seq =
-
+ module Seq =
/// Returns a new sequence that contains the cartesian product of the two input sequences.
/// The first sequence.
/// The second sequence.
@@ -25,7 +24,7 @@ namespace Microsoft.FSharp.Collections
/// Wraps the two given enumerations as a single concatenated
/// enumeration.
///
- /// The returned sequence may be passed between threads safely. However,
+ /// The returned sequence may be passed between threads safely. However,
/// individual IEnumerator values generated from the returned sequence should not be accessed
/// concurrently.
///
@@ -37,11 +36,11 @@ namespace Microsoft.FSharp.Collections
/// Thrown when either of the two provided sequences is
/// null.
[]
- val append: source1:seq<'T> -> source2:seq<'T> -> seq<'T>
+ val append: source1:seq<'T> -> source2:seq<'T> -> seq<'T>
/// Returns the average of the elements in the sequence.
///
- /// The elements are averaged using the + operator, DivideByInt method and Zero property
+ /// The elements are averaged using the + operator, DivideByInt method and Zero property
/// associated with the element type.
///
/// The input sequence.
@@ -51,15 +50,15 @@ namespace Microsoft.FSharp.Collections
/// Thrown when the input sequence is null.
/// Thrown when the input sequence has zero elements.
[]
- val inline average : source:seq<(^T)> -> ^T
- when ^T : (static member ( + ) : ^T * ^T -> ^T)
- and ^T : (static member DivideByInt : ^T * int -> ^T)
+ val inline average : source:seq<(^T)> -> ^T
+ when ^T : (static member ( + ) : ^T * ^T -> ^T)
+ and ^T : (static member DivideByInt : ^T * int -> ^T)
and ^T : (static member Zero : ^T)
- /// Returns the average of the results generated by applying the function to each element
+ /// Returns the average of the results generated by applying the function to each element
/// of the sequence.
///
- /// The elements are averaged using the + operator, DivideByInt method and Zero property
+ /// The elements are averaged using the + operator, DivideByInt method and Zero property
/// associated with the generated type.
///
/// A function applied to transform each element of the sequence.
@@ -70,29 +69,29 @@ namespace Microsoft.FSharp.Collections
/// Thrown when the input sequence is null.
/// Thrown when the input sequence has zero elements.
[]
- val inline averageBy : projection:('T -> ^U) -> source:seq<'T> -> ^U
- when ^U : (static member ( + ) : ^U * ^U -> ^U)
- and ^U : (static member DivideByInt : ^U * int -> ^U)
+ val inline averageBy : projection:('T -> ^U) -> source:seq<'T> -> ^U
+ when ^U : (static member ( + ) : ^U * ^U -> ^U)
+ and ^U : (static member DivideByInt : ^U * int -> ^U)
and ^U : (static member Zero : ^U)
/// Returns a sequence that corresponds to a cached version of the input sequence.
- /// This result sequence will have the same elements as the input sequence. The result
- /// can be enumerated multiple times. The input sequence will be enumerated at most
+ /// This result sequence will have the same elements as the input sequence. The result
+ /// can be enumerated multiple times. The input sequence will be enumerated at most
/// once and only as far as is necessary. Caching a sequence is typically useful when repeatedly
/// evaluating items in the original sequence is computationally expensive or if
/// iterating the sequence causes side-effects that the user does not want to be
/// repeated multiple times.
///
/// Enumeration of the result sequence is thread safe in the sense that multiple independent IEnumerator
- /// values may be used simultaneously from different threads (accesses to
+ /// values may be used simultaneously from different threads (accesses to
/// the internal lookaside table are thread safe). Each individual IEnumerator
/// is not typically thread safe and should not be accessed concurrently.
///
/// Once enumeration of the input sequence has started,
/// it's enumerator will be kept live by this object until the enumeration has completed.
- /// At that point, the enumerator will be disposed.
+ /// At that point, the enumerator will be disposed.
///
- /// The enumerator may be disposed and underlying cache storage released by
+ /// The enumerator may be disposed and underlying cache storage released by
/// converting the returned sequence object to type IDisposable, and calling the Dispose method
/// on this object. The sequence object may then be re-enumerated and a fresh enumerator will
/// be used.
@@ -111,7 +110,7 @@ namespace Microsoft.FSharp.Collections
/// An incorrect type annotation may result in runtime type
/// errors.
/// Individual IEnumerator values generated from the returned sequence should not be accessed concurrently.
- ///
+ ///
/// The input sequence.
///
/// The result sequence.
@@ -124,7 +123,7 @@ namespace Microsoft.FSharp.Collections
/// the list comprised of the results "x" for each element where
/// the function returns Some(x).
///
- /// The returned sequence may be passed between threads safely. However,
+ /// The returned sequence may be passed between threads safely. However,
/// individual IEnumerator values generated from the returned sequence should not
/// be accessed concurrently.
///
@@ -132,7 +131,7 @@ namespace Microsoft.FSharp.Collections
/// The input sequence of type T.
///
/// The result sequence.
- ///
+ ///
/// Thrown when the input sequence is null.
[]
val choose: chooser:('T -> 'U option) -> source:seq<'T> -> seq<'U>
@@ -180,7 +179,7 @@ namespace Microsoft.FSharp.Collections
/// Combines the given enumeration-of-enumerations as a single concatenated
/// enumeration.
///
- /// The returned sequence may be passed between threads safely. However,
+ /// The returned sequence may be passed between threads safely. However,
/// individual IEnumerator values generated from the returned sequence should not be accessed concurrently.
///
/// The input enumeration-of-enumerations.
@@ -201,10 +200,10 @@ namespace Microsoft.FSharp.Collections
/// Applies a key-generating function to each element of a sequence and returns a sequence yielding unique
/// keys and their number of occurrences in the original sequence.
- ///
- /// Note that this function returns a sequence that digests the whole initial sequence as soon as
- /// that sequence is iterated. As a result this function should not be used with
- /// large or infinite sequences. The function makes no assumption on the ordering of the original
+ ///
+ /// Note that this function returns a sequence that digests the whole initial sequence as soon as
+ /// that sequence is iterated. As a result this function should not be used with
+ /// large or infinite sequences. The function makes no assumption on the ordering of the original
/// sequence.
///
/// A function transforming each item of the input sequence into a key to be
@@ -220,7 +219,7 @@ namespace Microsoft.FSharp.Collections
/// Returns a sequence that is built from the given delayed specification of a
/// sequence.
///
- /// The input function is evaluated each time an IEnumerator for the sequence
+ /// The input function is evaluated each time an IEnumerator for the sequence
/// is requested.
///
/// The generating function for the sequence.
@@ -239,7 +238,7 @@ namespace Microsoft.FSharp.Collections
[]
val distinct: source:seq<'T> -> seq<'T> when 'T : equality
- /// Returns a sequence that contains no duplicate entries according to the
+ /// Returns a sequence that contains no duplicate entries according to the
/// generic hash and equality comparisons on the keys returned by the given key-generating function.
/// If an element occurs multiple times in the sequence then the later occurrences are discarded.
///
@@ -291,8 +290,8 @@ namespace Microsoft.FSharp.Collections
/// Tests if any element of the sequence satisfies the given predicate.
///
- /// The predicate is applied to the elements of the input sequence. If any application
- /// returns true then the overall result is true and no further elements are tested.
+ /// The predicate is applied to the elements of the input sequence. If any application
+ /// returns true then the overall result is true and no further elements are tested.
/// Otherwise, false is returned.
///
/// A function to test each item of the input sequence.
@@ -306,9 +305,9 @@ namespace Microsoft.FSharp.Collections
/// Tests if any pair of corresponding elements of the input sequences satisfies the given predicate.
///
- /// The predicate is applied to matching elements in the two sequences up to the lesser of the
- /// two lengths of the collections. If any application returns true then the overall result is
- /// true and no further elements are tested. Otherwise, false is returned. If one sequence is shorter than
+ /// The predicate is applied to matching elements in the two sequences up to the lesser of the
+ /// two lengths of the collections. If any application returns true then the overall result is
+ /// true and no further elements are tested. Otherwise, false is returned. If one sequence is shorter than
/// the other then the remaining elements of the longer sequence are ignored.
///
/// A function to test each pair of items from the input sequences.
@@ -324,7 +323,7 @@ namespace Microsoft.FSharp.Collections
/// Returns a new collection containing only the elements of the collection
/// for which the given predicate returns "true". This is a synonym for Seq.where.
///
- /// The returned sequence may be passed between threads safely. However,
+ /// The returned sequence may be passed between threads safely. However,
/// individual IEnumerator values generated from the returned sequence should not be accessed concurrently.
///
/// Remember sequence is lazy, effects are delayed until it is enumerated.
@@ -334,18 +333,18 @@ namespace Microsoft.FSharp.Collections
///
/// The result sequence.
///
- /// Thrown when the input sequence is null.
+ /// Thrown when the input sequence is null.
[]
val filter: predicate:('T -> bool) -> source:seq<'T> -> seq<'T>
/// Returns a new collection containing only the elements of the collection
/// for which the given predicate returns "true".
///
- /// The returned sequence may be passed between threads safely. However,
+ /// The returned sequence may be passed between threads safely. However,
/// individual IEnumerator values generated from the returned sequence should not be accessed concurrently.
///
/// Remember sequence is lazy, effects are delayed until it is enumerated.
- ///
+ ///
/// A synonym for Seq.filter.
///
/// A function to test whether each item in the input sequence should be included in the output.
@@ -353,7 +352,7 @@ namespace Microsoft.FSharp.Collections
///
/// The result sequence.
///
- /// Thrown when the input sequence is null.
+ /// Thrown when the input sequence is null.
[]
val where: predicate:('T -> bool) -> source:seq<'T> -> seq<'T>
@@ -410,7 +409,7 @@ namespace Microsoft.FSharp.Collections
val findIndexBack: predicate:('T -> bool) -> source:seq<'T> -> int
/// Applies a function to each element of the collection, threading an accumulator argument
- /// through the computation. If the input function is f and the elements are i0...iN
+ /// through the computation. If the input function is f and the elements are i0...iN
/// then computes f (... (f s i0)...) iN
///
/// A function that updates the state with each element from the sequence.
@@ -464,8 +463,8 @@ namespace Microsoft.FSharp.Collections
/// Tests if all elements of the sequence satisfy the given predicate.
///
- /// The predicate is applied to the elements of the input sequence. If any application
- /// returns false then the overall result is false and no further elements are tested.
+ /// The predicate is applied to the elements of the input sequence. If any application
+ /// returns false then the overall result is false and no further elements are tested.
/// Otherwise, true is returned.
///
/// A function to test an element of the input sequence.
@@ -478,7 +477,7 @@ namespace Microsoft.FSharp.Collections
val forall: predicate:('T -> bool) -> source:seq<'T> -> bool
/// Tests the all pairs of elements drawn from the two sequences satisfy the
- /// given predicate. If one sequence is shorter than
+ /// given predicate. If one sequence is shorter than
/// the other then the remaining elements of the longer sequence are ignored.
///
/// A function to test pairs of elements from the input sequences.
@@ -491,13 +490,13 @@ namespace Microsoft.FSharp.Collections
[]
val forall2: predicate:('T1 -> 'T2 -> bool) -> source1:seq<'T1> -> source2:seq<'T2> -> bool
- /// Applies a key-generating function to each element of a sequence and yields a sequence of
- /// unique keys. Each unique key contains a sequence of all elements that match
+ /// Applies a key-generating function to each element of a sequence and yields a sequence of
+ /// unique keys. Each unique key contains a sequence of all elements that match
/// to this key.
- ///
- /// This function returns a sequence that digests the whole initial sequence as soon as
- /// that sequence is iterated. As a result this function should not be used with
- /// large or infinite sequences. The function makes no assumption on the ordering of the original
+ ///
+ /// This function returns a sequence that digests the whole initial sequence as soon as
+ /// that sequence is iterated. As a result this function should not be used with
+ /// large or infinite sequences. The function makes no assumption on the ordering of the original
/// sequence.
///
/// A function that transforms an element of the sequence into a comparable key.
@@ -581,7 +580,7 @@ namespace Microsoft.FSharp.Collections
/// initialization. The function is passed the index of the item being
/// generated.
///
- /// The returned sequence may be passed between threads safely. However,
+ /// The returned sequence may be passed between threads safely. However,
/// individual IEnumerator values generated from the returned sequence should not be accessed concurrently.
///
/// The maximum number of items to generate for the sequence.
@@ -592,14 +591,14 @@ namespace Microsoft.FSharp.Collections
/// Thrown when count is negative.
[]
val init: count:int -> initializer:(int -> 'T) -> seq<'T>
-
+
/// Generates a new sequence which, when iterated, will return successive
/// elements by calling the given function. The results of calling the function
/// will not be saved, that is the function will be reapplied as necessary to
/// regenerate the elements. The function is passed the index of the item being
/// generated.
///
- /// The returned sequence may be passed between threads safely. However,
+ /// The returned sequence may be passed between threads safely. However,
/// individual IEnumerator values generated from the returned sequence should not be accessed concurrently.
/// Iteration can continue up to Int32.MaxValue.
///
@@ -637,7 +636,7 @@ namespace Microsoft.FSharp.Collections
[]
val iteri: action:(int -> 'T -> unit) -> source:seq<'T> -> unit
- /// Applies the given function to two collections simultaneously. If one sequence is shorter than
+ /// Applies the given function to two collections simultaneously. If one sequence is shorter than
/// the other then the remaining elements of the longer sequence are ignored.
///
/// A function to apply to each pair of elements from the input sequences.
@@ -648,7 +647,7 @@ namespace Microsoft.FSharp.Collections
[]
val iter2: action:('T1 -> 'T2 -> unit) -> source1:seq<'T1> -> source2:seq<'T2> -> unit
- /// Applies the given function to two collections simultaneously. If one sequence is shorter than
+ /// Applies the given function to two collections simultaneously. If one sequence is shorter than
/// the other then the remaining elements of the longer sequence are ignored. The integer passed to the
/// function indicates the index of element.
///
@@ -675,7 +674,7 @@ namespace Microsoft.FSharp.Collections
/// as elements are demanded using the MoveNext method on enumerators retrieved from the
/// object.
///
- /// The returned sequence may be passed between threads safely. However,
+ /// The returned sequence may be passed between threads safely. However,
/// individual IEnumerator values generated from the returned sequence should not be accessed concurrently.
///
/// A function to transform items from the input sequence.
@@ -688,7 +687,7 @@ namespace Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>
/// Builds a new collection whose elements are the results of applying the given function
- /// to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than
+ /// to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than
/// the other then the remaining elements of the longer sequence are ignored.
///
/// A function to transform pairs of items from the input sequences.
@@ -756,7 +755,7 @@ namespace Microsoft.FSharp.Collections
val mapi: mapping:(int -> 'T -> 'U) -> source:seq<'T> -> seq<'U>
/// Builds a new collection whose elements are the results of applying the given function
- /// to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than
+ /// to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than
/// the other then the remaining elements of the longer sequence are ignored. The integer index passed to the
/// function indicates the index (from 0) of element being transformed.
///
@@ -779,7 +778,7 @@ namespace Microsoft.FSharp.Collections
///
/// The largest element of the sequence.
[]
- val inline max : source:seq<'T> -> 'T when 'T : comparison
+ val inline max : source:seq<'T> -> 'T when 'T : comparison
/// Returns the greatest of all elements of the sequence, compared via Operators.max on the function result.
///
@@ -791,7 +790,7 @@ namespace Microsoft.FSharp.Collections
/// Thrown when the input sequence is null.
/// Thrown when the input sequence is empty.
[]
- val inline maxBy : projection:('T -> 'U) -> source:seq<'T> -> 'T when 'U : comparison
+ val inline maxBy : projection:('T -> 'U) -> source:seq<'T> -> 'T when 'U : comparison
(*
/// Returns the greatest function result from the elements of the sequence, compared via Operators.max.
@@ -804,7 +803,7 @@ namespace Microsoft.FSharp.Collections
/// Thrown when the input sequence is null.
/// Thrown when the input sequence is empty.
[]
- val inline maxValBy : projection:('T -> 'U) -> source:seq<'T> -> 'U when 'U : comparison
+ val inline maxValBy : projection:('T -> 'U) -> source:seq<'T> -> 'U when 'U : comparison
*)
/// Returns the lowest of all elements of the sequence, compared via Operators.min.
@@ -816,7 +815,7 @@ namespace Microsoft.FSharp.Collections
/// Thrown when the input sequence is null.
/// Thrown when the input sequence is empty.
[]
- val inline min : source:seq<'T> -> 'T when 'T : comparison
+ val inline min : source:seq<'T> -> 'T when 'T : comparison
/// Returns the lowest of all elements of the sequence, compared via Operators.min on the function result.
///
@@ -828,7 +827,7 @@ namespace Microsoft.FSharp.Collections
/// Thrown when the input sequence is null.
/// Thrown when the input sequence is empty.
[]
- val inline minBy : projection:('T -> 'U) -> source:seq<'T> -> 'T when 'U : comparison
+ val inline minBy : projection:('T -> 'U) -> source:seq<'T> -> 'T when 'U : comparison
(*
/// Returns the lowest function result from the elements of the sequence, compared via Operators.max.
@@ -841,7 +840,7 @@ namespace Microsoft.FSharp.Collections
/// Thrown when the input sequence is null.
/// Thrown when the input sequence is empty.
[]
- val inline minValBy : projection:('T -> 'U) -> source:seq<'T> -> 'U when 'U : comparison
+ val inline minValBy : projection:('T -> 'U) -> source:seq<'T> -> 'U when 'U : comparison
*)
/// Computes the nth element in the collection.
@@ -917,10 +916,10 @@ namespace Microsoft.FSharp.Collections
/// Thrown when every item of the sequence
/// evaluates to None when the given function is applied.
[]
- val pick: chooser:('T -> 'U option) -> source:seq<'T> -> 'U
+ val pick: chooser:('T -> 'U option) -> source:seq<'T> -> 'U
- /// Builds a new sequence object that delegates to the given sequence object. This ensures
- /// the original sequence cannot be rediscovered and mutated by a type cast. For example,
+ /// Builds a new sequence object that delegates to the given sequence object. This ensures
+ /// the original sequence cannot be rediscovered and mutated by a type cast. For example,
/// if given an array the returned sequence will return the elements of the array, but
/// you cannot cast the returned sequence object to an array.
///
@@ -934,7 +933,7 @@ namespace Microsoft.FSharp.Collections
/// Applies a function to each element of the sequence, threading an accumulator argument
/// through the computation. Begin by applying the function to the first two elements.
- /// Then feed this result into the function along with the third element and so on.
+ /// Then feed this result into the function along with the third element and so on.
/// Return the final result.
///
/// A function that takes in the current accumulated result and the next
@@ -956,7 +955,7 @@ namespace Microsoft.FSharp.Collections
val replicate: count:int -> initial:'T -> seq<'T>
/// Applies a function to each element of the sequence, starting from the end, threading an accumulator argument
- /// through the computation. If the input function is f and the elements are i0...iN
+ /// through the computation. If the input function is f and the elements are i0...iN
/// then computes f i0 (...(f iN-1 iN)).
/// A function that takes in the next-to-last element of the sequence and the
/// current accumulated result to produce the next accumulated result.
@@ -1023,7 +1022,7 @@ namespace Microsoft.FSharp.Collections
[]
val skip: count:int -> source:seq<'T> -> seq<'T>
- /// Returns a sequence that, when iterated, skips elements of the underlying sequence while the
+ /// Returns a sequence that, when iterated, skips elements of the underlying sequence while the
/// given predicate returns True, and then yields the remaining elements of the sequence.
///
/// A function that evaluates an element of the sequence to a boolean value.
@@ -1036,10 +1035,10 @@ namespace Microsoft.FSharp.Collections
val skipWhile: predicate:('T -> bool) -> source:seq<'T> -> seq<'T>
/// Yields a sequence ordered by keys.
- ///
- /// This function returns a sequence that digests the whole initial sequence as soon as
- /// that sequence is iterated. As a result this function should not be used with
- /// large or infinite sequences. The function makes no assumption on the ordering of the original
+ ///
+ /// This function returns a sequence that digests the whole initial sequence as soon as
+ /// that sequence is iterated. As a result this function should not be used with
+ /// large or infinite sequences. The function makes no assumption on the ordering of the original
/// sequence.
///
/// This is a stable sort, that is the original order of equal elements is preserved.
@@ -1068,11 +1067,11 @@ namespace Microsoft.FSharp.Collections
val sortWith : comparer:('T -> 'T -> int) -> source:seq<'T> -> seq<'T>
/// Applies a key-generating function to each element of a sequence and yield a sequence ordered
- /// by keys. The keys are compared using generic comparison as implemented by Operators.compare.
- ///
- /// This function returns a sequence that digests the whole initial sequence as soon as
- /// that sequence is iterated. As a result this function should not be used with
- /// large or infinite sequences. The function makes no assumption on the ordering of the original
+ /// by keys. The keys are compared using generic comparison as implemented by Operators.compare.
+ ///
+ /// This function returns a sequence that digests the whole initial sequence as soon as
+ /// that sequence is iterated. As a result this function should not be used with
+ /// large or infinite sequences. The function makes no assumption on the ordering of the original
/// sequence.
///
/// This is a stable sort, that is the original order of equal elements is preserved.
@@ -1084,13 +1083,13 @@ namespace Microsoft.FSharp.Collections
///
/// Thrown when the input sequence is null.
[]
- val sortBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> when 'Key : comparison
+ val sortBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> when 'Key : comparison
/// Yields a sequence ordered descending by keys.
- ///
- /// This function returns a sequence that digests the whole initial sequence as soon as
- /// that sequence is iterated. As a result this function should not be used with
- /// large or infinite sequences. The function makes no assumption on the ordering of the original
+ ///
+ /// This function returns a sequence that digests the whole initial sequence as soon as
+ /// that sequence is iterated. As a result this function should not be used with
+ /// large or infinite sequences. The function makes no assumption on the ordering of the original
/// sequence.
///
/// This is a stable sort, that is the original order of equal elements is preserved.
@@ -1104,11 +1103,11 @@ namespace Microsoft.FSharp.Collections
val inline sortDescending : source:seq<'T> -> seq<'T> when 'T : comparison
/// Applies a key-generating function to each element of a sequence and yield a sequence ordered
- /// descending by keys. The keys are compared using generic comparison as implemented by Operators.compare.
- ///
- /// This function returns a sequence that digests the whole initial sequence as soon as
- /// that sequence is iterated. As a result this function should not be used with
- /// large or infinite sequences. The function makes no assumption on the ordering of the original
+ /// descending by keys. The keys are compared using generic comparison as implemented by Operators.compare.
+ ///
+ /// This function returns a sequence that digests the whole initial sequence as soon as
+ /// that sequence is iterated. As a result this function should not be used with
+ /// large or infinite sequences. The function makes no assumption on the ordering of the original
/// sequence.
///
/// This is a stable sort, that is the original order of equal elements is preserved.
@@ -1130,8 +1129,8 @@ namespace Microsoft.FSharp.Collections
///
/// The computed sum.
[]
- val inline sum : source:seq<(^T)> -> ^T
- when ^T : (static member ( + ) : ^T * ^T -> ^T)
+ val inline sum : source:seq<(^T)> -> ^T
+ when ^T : (static member ( + ) : ^T * ^T -> ^T)
and ^T : (static member Zero : ^T)
/// Returns the sum of the results generated by applying the function to each element of the sequence.
@@ -1142,8 +1141,8 @@ namespace Microsoft.FSharp.Collections
///
/// The computed sum.
[]
- val inline sumBy : projection:('T -> ^U) -> source:seq<'T> -> ^U
- when ^U : (static member ( + ) : ^U * ^U -> ^U)
+ val inline sumBy : projection:('T -> ^U) -> source:seq<'T> -> ^U
+ when ^U : (static member ( + ) : ^U * ^U -> ^U)
and ^U : (static member Zero : ^U)
/// Returns a sequence that skips 1 element of the underlying sequence and then yields the
@@ -1175,7 +1174,7 @@ namespace Microsoft.FSharp.Collections
[]
val take: count:int -> source:seq<'T> -> seq<'T>
- /// Returns a sequence that, when iterated, yields elements of the underlying sequence while the
+ /// Returns a sequence that, when iterated, yields elements of the underlying sequence while the
/// given predicate returns True, and then returns no further elements.
///
/// A function that evaluates to false when no more items should be returned.
@@ -1197,6 +1196,16 @@ namespace Microsoft.FSharp.Collections
[]
val toArray: source:seq<'T> -> 'T[]
+ /// Builds an SeqEnumerable from the given collection.
+ ///
+ /// The input sequence.
+ ///
+ /// The result SeqEnumerable.
+ ///
+ /// Thrown when the input sequence is null.
+ []
+ val toComposer : source:seq<'T> -> Composer.Core.ISeq<'T>
+
/// Builds a list from the given collection.
///
/// The input sequence.
@@ -1231,7 +1240,7 @@ namespace Microsoft.FSharp.Collections
[]
val tryFindBack: predicate:('T -> bool) -> source:seq<'T> -> 'T option
- /// Returns the index of the first element in the sequence
+ /// Returns the index of the first element in the sequence
/// that satisfies the given predicate. Return None if no such element exists.
///
/// A function that evaluates to a Boolean when given an item in the sequence.
@@ -1295,7 +1304,7 @@ namespace Microsoft.FSharp.Collections
///
/// The stream will be recomputed each time an IEnumerator is requested and iterated for the Seq.
///
- /// The returned sequence may be passed between threads safely. However,
+ /// The returned sequence may be passed between threads safely. However,
/// individual IEnumerator values generated from the returned sequence should not be accessed concurrently.
///
/// A function that takes in the current state and returns an option tuple of the next
@@ -1341,98 +1350,4 @@ namespace Microsoft.FSharp.Collections
///
/// Thrown when any of the input sequences is null.
[]
- val zip3: source1:seq<'T1> -> source2:seq<'T2> -> source3:seq<'T3> -> seq<'T1 * 'T2 * 'T3>
-
-namespace Microsoft.FSharp.Core.CompilerServices
-
- open System
- open System.Collections
- open System.Collections.Generic
- open Microsoft.FSharp.Core
- open Microsoft.FSharp.Collections
-
-
- []
- /// A group of functions used as part of the compiled representation of F# sequence expressions.
- module RuntimeHelpers =
-
- []
- type internal StructBox<'T when 'T : equality> =
- new : value:'T -> StructBox<'T>
- member Value : 'T
- static member Comparer : IEqualityComparer>
-
- /// The F# compiler emits calls to this function to
- /// implement the while operator for F# sequence expressions.
- ///
- /// A function that indicates whether iteration should continue.
- /// The input sequence.
- ///
- /// The result sequence.
- val EnumerateWhile : guard:(unit -> bool) -> source:seq<'T> -> seq<'T>
-
- /// The F# compiler emits calls to this function to
- /// implement the try/finally operator for F# sequence expressions.
- ///
- /// The input sequence.
- /// A computation to be included in an enumerator's Dispose method.
- ///
- /// The result sequence.
- val EnumerateThenFinally : source:seq<'T> -> compensation:(unit -> unit) -> seq<'T>
-
- /// The F# compiler emits calls to this function to implement the compiler-intrinsic
- /// conversions from untyped System.Collections.IEnumerable sequences to typed sequences.
- ///
- /// An initializer function.
- /// A function to iterate and test if end of sequence is reached.
- /// A function to retrieve the current element.
- ///
- /// The resulting typed sequence.
- val EnumerateFromFunctions: create:(unit -> 'T) -> moveNext:('T -> bool) -> current:('T -> 'U) -> seq<'U>
-
- /// The F# compiler emits calls to this function to implement the use operator for F# sequence
- /// expressions.
- ///
- /// The resource to be used and disposed.
- /// The input sequence.
- ///
- /// The result sequence.
- val EnumerateUsing : resource:'T -> source:('T -> 'Collection) -> seq<'U> when 'T :> IDisposable and 'Collection :> seq<'U>
-
- /// Creates an anonymous event with the given handlers.
- ///
- /// A function to handle adding a delegate for the event to trigger.
- /// A function to handle removing a delegate that the event triggers.
- /// A function to produce the delegate type the event can trigger.
- ///
- /// The initialized event.
- val CreateEvent : addHandler : ('Delegate -> unit) -> removeHandler : ('Delegate -> unit) -> createHandler : ((obj -> 'Args -> unit) -> 'Delegate) -> Microsoft.FSharp.Control.IEvent<'Delegate,'Args>
-
- []
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- type GeneratedSequenceBase<'T> =
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- ///
- /// A new sequence generator for the expression.
- new : unit -> GeneratedSequenceBase<'T>
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- ///
- /// A new enumerator for the sequence.
- abstract GetFreshEnumerator : unit -> IEnumerator<'T>
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- ///
- /// A reference to the sequence.
- ///
- /// A 0, 1, and 2 respectively indicate Stop, Yield, and Goto conditions for the sequence generator.
- abstract GenerateNext : result:byref> -> int
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- abstract Close: unit -> unit
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- abstract CheckClose: bool
- /// The F# compiler emits implementations of this type for compiled sequence expressions.
- abstract LastGenerated : 'T
- interface IEnumerable<'T>
- interface IEnumerable
- interface IEnumerator<'T>
- interface IEnumerator
-
+ val zip3: source1:seq<'T1> -> source2:seq<'T2> -> source3:seq<'T3> -> seq<'T1 * 'T2 * 'T3>
\ No newline at end of file
diff --git a/src/fsharp/FSharp.Core/seqcomposer.fs b/src/fsharp/FSharp.Core/seqcomposer.fs
new file mode 100644
index 00000000000..0026fa3a2b8
--- /dev/null
+++ b/src/fsharp/FSharp.Core/seqcomposer.fs
@@ -0,0 +1,1688 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.FSharp.Collections
+
+ open System
+ open System.Diagnostics
+ open System.Collections
+ open System.Collections.Generic
+ open System.Reflection
+ open Microsoft.FSharp.Core
+ open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
+ open Microsoft.FSharp.Core.Operators
+ open Microsoft.FSharp.Core.CompilerServices
+ open Microsoft.FSharp.Control
+ open Microsoft.FSharp.Collections
+ open Microsoft.FSharp.Primitives.Basics
+
+ []
+ module Composer =
+ open IEnumerator
+
+ module Core =
+ []
+ type NoValue = struct end
+
+ []
+ type Value<'a> =
+ val mutable _1 : 'a
+ new (a:'a) = { _1 = a }
+
+ []
+ type Values<'a,'b> =
+ val mutable _1 : 'a
+ val mutable _2 : 'b
+ new (a:'a, b: 'b) = { _1 = a; _2 = b }
+
+ []
+ type Values<'a,'b,'c> =
+ val mutable _1 : 'a
+ val mutable _2 : 'b
+ val mutable _3 : 'c
+ new (a:'a, b:'b, c:'c) = { _1 = a; _2 = b; _3 = c }
+
+ type PipeIdx = int
+
+ type IOutOfBand =
+ abstract StopFurtherProcessing : PipeIdx -> unit
+
+ []
+ type Activity() =
+ abstract ChainComplete : stopTailCall:byref * PipeIdx -> unit
+ abstract ChainDispose : stopTailCall:byref -> unit
+
+ []
+ type Activity<'T,'U> () =
+ inherit Activity()
+ abstract ProcessNext : input:'T -> bool
+
+ []
+ type Transform<'T,'U,'State> =
+ inherit Activity<'T,'U>
+
+ new (next:Activity, initState:'State) = {
+ inherit Activity<'T,'U> ()
+ State = initState
+ Next = next
+ }
+
+ val mutable State : 'State
+ val Next : Activity
+
+ override this.ChainComplete (stopTailCall, terminatingIdx) =
+ this.Next.ChainComplete (&stopTailCall, terminatingIdx)
+ override this.ChainDispose stopTailCall =
+ this.Next.ChainDispose (&stopTailCall)
+
+ []
+ type TransformWithPostProcessing<'T,'U,'State>(next:Activity, initState:'State) =
+ inherit Transform<'T,'U,'State>(next, initState)
+
+ abstract OnComplete : PipeIdx -> unit
+ abstract OnDispose : unit -> unit
+
+ override this.ChainComplete (stopTailCall, terminatingIdx) =
+ this.OnComplete terminatingIdx
+ this.Next.ChainComplete (&stopTailCall, terminatingIdx)
+ override this.ChainDispose stopTailCall =
+ try this.OnDispose ()
+ finally this.Next.ChainDispose (&stopTailCall)
+
+ []
+ type Folder<'T,'Result,'State> =
+ inherit Activity<'T,'T>
+
+ val mutable Result : 'Result
+ val mutable State : 'State
+
+ val mutable HaltedIdx : int
+ member this.StopFurtherProcessing pipeIdx = this.HaltedIdx <- pipeIdx
+ interface IOutOfBand with
+ member this.StopFurtherProcessing pipeIdx = this.StopFurtherProcessing pipeIdx
+
+ new (initalResult,initState) = {
+ inherit Activity<'T,'T>()
+ State = initState
+ HaltedIdx = 0
+ Result = initalResult
+ }
+
+ override this.ChainComplete (_,_) = ()
+ override this.ChainDispose _ = ()
+
+ []
+ type FolderWithPostProcessing<'T,'Result,'State>(initResult,initState) =
+ inherit Folder<'T,'Result,'State>(initResult,initState)
+
+ abstract OnComplete : PipeIdx -> unit
+ abstract OnDispose : unit -> unit
+
+ override this.ChainComplete (stopTailCall, terminatingIdx) =
+ this.OnComplete terminatingIdx
+ override this.ChainDispose _ =
+ this.OnDispose ()
+
+ []
+ type TransformFactory<'T,'U> () =
+ abstract Compose<'V> : IOutOfBand -> PipeIdx -> Activity<'U,'V> -> Activity<'T,'V>
+
+ type ISeq<'T> =
+ inherit IEnumerable<'T>
+ abstract member PushTransform<'U> : TransformFactory<'T,'U> -> ISeq<'U>
+ abstract member Fold<'Result,'State> : f:(PipeIdx->Folder<'T,'Result,'State>) -> 'Result
+
+ open Core
+
+ module internal TailCall =
+ // used for performance reasons; these are not recursive calls, so should be safe
+ // ** it should be noted that potential changes to the f# compiler may render this function
+ // ineffictive **
+ let inline avoid boolean = match boolean with true -> true | false -> false
+
+ module internal Upcast =
+ // The f# compiler outputs unnecessary unbox.any calls in upcasts. If this functionality
+ // is fixed with the compiler then these functions can be removed.
+ let inline seq<'T,'seq when 'seq :> ISeq<'T> and 'seq : not struct> (t:'seq) : ISeq<'T> = (# "" t : ISeq<'T> #)
+ let inline enumerable<'T,'enumerable when 'enumerable :> IEnumerable<'T> and 'enumerable : not struct> (t:'enumerable) : IEnumerable<'T> = (# "" t : IEnumerable<'T> #)
+ let inline enumerator<'T,'enumerator when 'enumerator :> IEnumerator<'T> and 'enumerator : not struct> (t:'enumerator) : IEnumerator<'T> = (# "" t : IEnumerator<'T> #)
+ let inline enumeratorNonGeneric<'enumerator when 'enumerator :> IEnumerator and 'enumerator : not struct> (t:'enumerator) : IEnumerator = (# "" t : IEnumerator #)
+ let inline outOfBand<'outOfBand when 'outOfBand :> IOutOfBand and 'outOfBand : not struct> (t:'outOfBand) : IOutOfBand = (# "" t : IOutOfBand #)
+
+ let createFold (factory:TransformFactory<_,_>) (folder:Folder<_,_,_>) pipeIdx =
+ factory.Compose (Upcast.outOfBand folder) pipeIdx folder
+
+ let inline valueComparer<'T when 'T : equality> ()=
+ let c = HashIdentity.Structural<'T>
+ { new IEqualityComparer> with
+ member __.GetHashCode o = c.GetHashCode o._1
+ member __.Equals (lhs,rhs) = c.Equals (lhs._1, rhs._1) }
+
+ type ComposedFactory<'T,'U,'V> private (first:TransformFactory<'T,'U>, second:TransformFactory<'U,'V>) =
+ inherit TransformFactory<'T,'V>()
+
+ override this.Compose<'W> (outOfBand:IOutOfBand) (pipeIdx:PipeIdx) (next:Activity<'V,'W>) : Activity<'T,'W> =
+ first.Compose outOfBand (pipeIdx-1) (second.Compose outOfBand pipeIdx next)
+
+ static member Combine (first:TransformFactory<'T,'U>) (second:TransformFactory<'U,'V>) : TransformFactory<'T,'V> =
+ upcast ComposedFactory(first, second)
+
+ and IdentityFactory<'T> private () =
+ inherit TransformFactory<'T,'T> ()
+ static let singleton : TransformFactory<'T,'T> = upcast (IdentityFactory<'T>())
+ override __.Compose<'V> (_outOfBand:IOutOfBand) (_pipeIdx:PipeIdx) (next:Activity<'T,'V>) : Activity<'T,'V> = next
+ static member Instance = singleton
+
+ and ISkipable =
+ // Seq.init(Infinite)? lazily uses Current. The only Composer component that can do that is Skip
+ // and it can only do it at the start of a sequence
+ abstract CanSkip : unit -> bool
+
+ type SeqProcessNextStates =
+ | InProcess = 0
+ | NotStarted = 1
+ | Finished = 2
+
+ type Result<'T>() =
+ inherit Folder<'T,'T,NoValue>(Unchecked.defaultof<'T>,Unchecked.defaultof)
+
+ member val SeqState = SeqProcessNextStates.NotStarted with get, set
+
+ override this.ProcessNext (input:'T) : bool =
+ this.Result <- input
+ true
+
+ module Fold =
+ type IIterate<'T> =
+ abstract Iterate<'U,'Result,'State> : outOfBand:Folder<'U,'Result,'State> -> consumer:Activity<'T,'U> -> unit
+
+ []
+ type enumerable<'T> (enumerable:IEnumerable<'T>) =
+ interface IIterate<'T> with
+ member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) =
+ use enumerator = enumerable.GetEnumerator ()
+ let rec iterate () =
+ if enumerator.MoveNext () then
+ consumer.ProcessNext enumerator.Current |> ignore
+ if outOfBand.HaltedIdx = 0 then
+ iterate ()
+ iterate ()
+
+ []
+ type Array<'T> (array:array<'T>) =
+ interface IIterate<'T> with
+ member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) =
+ let array = array
+ let rec iterate idx =
+ if idx < array.Length then
+ consumer.ProcessNext array.[idx] |> ignore
+ if outOfBand.HaltedIdx = 0 then
+ iterate (idx+1)
+ iterate 0
+
+ []
+ type resizeArray<'T> (array:ResizeArray<'T>) =
+ interface IIterate<'T> with
+ member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) =
+ let array = array
+ let rec iterate idx =
+ if idx < array.Count then
+ consumer.ProcessNext array.[idx] |> ignore
+ if outOfBand.HaltedIdx = 0 then
+ iterate (idx+1)
+ iterate 0
+
+ []
+ type List<'T> (alist:list<'T>) =
+ interface IIterate<'T> with
+ member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) =
+ let rec iterate lst =
+ match lst with
+ | hd :: tl ->
+ consumer.ProcessNext hd |> ignore
+ if outOfBand.HaltedIdx = 0 then
+ iterate tl
+ | _ -> ()
+ iterate alist
+
+ []
+ type unfold<'S,'T> (generator:'S->option<'T*'S>, state:'S) =
+ interface IIterate<'T> with
+ member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) =
+ let generator = generator
+ let rec iterate current =
+ match generator current with
+ | Some (item, next) ->
+ consumer.ProcessNext item |> ignore
+ if outOfBand.HaltedIdx = 0 then
+ iterate next
+ | _ -> ()
+ iterate state
+
+ []
+ type init<'T> (f:int->'T, terminatingIdx:int) =
+ interface IIterate<'T> with
+ member __.Iterate (outOfBand:Folder<'U,'Result,'State>) (consumer:Activity<'T,'U>) =
+ let terminatingIdx = terminatingIdx
+ let f = f
+
+ let firstIdx =
+ match box consumer with
+ | :? ISkipable as skipping ->
+ let rec skip idx =
+ if idx = terminatingIdx || outOfBand.HaltedIdx <> 0 then
+ terminatingIdx
+ elif skipping.CanSkip () then
+ skip (idx+1)
+ else
+ idx
+ skip -1
+ | _ -> -1
+
+ let rec iterate idx =
+ if idx < terminatingIdx then
+ consumer.ProcessNext (f (idx+1)) |> ignore
+ if outOfBand.HaltedIdx = 0 then
+ iterate (idx+1)
+ else
+ idx
+ else
+ idx
+
+ let finalIdx = iterate firstIdx
+ if outOfBand.HaltedIdx = 0 && finalIdx = System.Int32.MaxValue then
+ raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue))
+
+ let execute (createFolder:PipeIdx->Folder<'U,'Result,'State>) (transformFactory:TransformFactory<'T,'U>) pipeIdx (executeOn:#IIterate<'T>) =
+ let mutable stopTailCall = ()
+ let result = createFolder (pipeIdx+1)
+ let consumer = createFold transformFactory result pipeIdx
+ try
+ executeOn.Iterate result consumer
+ consumer.ChainComplete (&stopTailCall, result.HaltedIdx)
+ result.Result
+ finally
+ consumer.ChainDispose (&stopTailCall)
+
+ let executeThin (createFolder:PipeIdx->Folder<'T,'Result,'State>) (executeOn:#IIterate<'T>) =
+ let mutable stopTailCall = ()
+ let result = createFolder 1
+ try
+ executeOn.Iterate result result
+ result.ChainComplete (&stopTailCall, result.HaltedIdx)
+ result.Result
+ finally
+ result.ChainDispose (&stopTailCall)
+
+ module Enumerable =
+ type Empty<'T>() =
+ let current () = failwith "library implementation error: Current should never be called"
+ interface IEnumerator<'T> with
+ member __.Current = current ()
+ interface IEnumerator with
+ member __.Current = current ()
+ member __.MoveNext () = false
+ member __.Reset (): unit = noReset ()
+ interface IDisposable with
+ member __.Dispose () = ()
+
+ type EmptyEnumerators<'T>() =
+ static let element : IEnumerator<'T> = upcast (new Empty<'T> ())
+ static member Element = element
+
+ []
+ type EnumeratorBase<'T>(result:Result<'T>, activity:Activity) =
+ interface IDisposable with
+ member __.Dispose () : unit =
+ let mutable stopTailCall = ()
+ activity.ChainDispose (&stopTailCall)
+
+ interface IEnumerator with
+ member this.Current : obj = box ((Upcast.enumerator this)).Current
+ member __.MoveNext () = failwith "library implementation error: derived class should implement (should be abstract)"
+ member __.Reset () : unit = noReset ()
+
+ interface IEnumerator<'T> with
+ member __.Current =
+ if result.SeqState = SeqProcessNextStates.InProcess then result.Result
+ else
+ match result.SeqState with
+ | SeqProcessNextStates.NotStarted -> notStarted()
+ | SeqProcessNextStates.Finished -> alreadyFinished()
+ | _ -> failwith "library implementation error: all states should have been handled"
+
+ and [] EnumerableBase<'T> () =
+ let derivedClassShouldImplement () =
+ failwith "library implementation error: derived class should implement (should be abstract)"
+
+ abstract member Append : (ISeq<'T>) -> ISeq<'T>
+
+ default this.Append source = Upcast.seq (AppendEnumerable [this; source])
+
+ interface IEnumerable with
+ member this.GetEnumerator () : IEnumerator =
+ let genericEnumerable = Upcast.enumerable this
+ let genericEnumerator = genericEnumerable.GetEnumerator ()
+ Upcast.enumeratorNonGeneric genericEnumerator
+
+ interface IEnumerable<'T> with
+ member this.GetEnumerator () : IEnumerator<'T> = derivedClassShouldImplement ()
+
+ interface ISeq<'T> with
+ member __.PushTransform _ = derivedClassShouldImplement ()
+ member __.Fold _ = derivedClassShouldImplement ()
+
+ and Enumerator<'T,'U>(source:IEnumerator<'T>, activity:Activity<'T,'U>, result:Result<'U>) =
+ inherit EnumeratorBase<'U>(result, activity)
+
+ let rec moveNext () =
+ if (result.HaltedIdx = 0) && source.MoveNext () then
+ if activity.ProcessNext source.Current then
+ true
+ else
+ moveNext ()
+ else
+ result.SeqState <- SeqProcessNextStates.Finished
+ let mutable stopTailCall = ()
+ activity.ChainComplete (&stopTailCall, result.HaltedIdx)
+ false
+
+ interface IEnumerator with
+ member __.MoveNext () =
+ result.SeqState <- SeqProcessNextStates.InProcess
+ moveNext ()
+
+ interface IDisposable with
+ member __.Dispose () =
+ try
+ source.Dispose ()
+ finally
+ let mutable stopTailCall = ()
+ activity.ChainDispose (&stopTailCall)
+
+ and Enumerable<'T,'U>(enumerable:IEnumerable<'T>, current:TransformFactory<'T,'U>, pipeIdx:PipeIdx) =
+ inherit EnumerableBase<'U>()
+
+ interface IEnumerable<'U> with
+ member this.GetEnumerator () : IEnumerator<'U> =
+ let result = Result<'U> ()
+ Upcast.enumerator (new Enumerator<'T,'U>(enumerable.GetEnumerator(), createFold current result pipeIdx, result))
+
+ interface ISeq<'U> with
+ member __.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> =
+ Upcast.seq (new Enumerable<'T,'V>(enumerable, ComposedFactory.Combine current next, pipeIdx+1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) =
+ Fold.execute f current pipeIdx (Fold.enumerable enumerable)
+
+ and EnumerableThin<'T>(enumerable:IEnumerable<'T>) =
+ inherit EnumerableBase<'T>()
+
+ interface IEnumerable<'T> with
+ member this.GetEnumerator () = enumerable.GetEnumerator ()
+
+ interface ISeq<'T> with
+ member __.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> =
+ Upcast.seq (new Enumerable<'T,'U>(enumerable, next, 1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) =
+ Fold.executeThin f (Fold.enumerable enumerable)
+
+ and SeqDelayed<'T>(delayed:unit->ISeq<'T>, pipeIdx:PipeIdx) =
+ inherit EnumerableBase<'T>()
+
+ interface IEnumerable<'T> with
+ member this.GetEnumerator () : IEnumerator<'T> = (delayed()).GetEnumerator ()
+
+ interface ISeq<'T> with
+ member __.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> =
+ Upcast.seq (new SeqDelayed<'U>((fun () -> (delayed()).PushTransform next), pipeIdx+1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) =
+ (delayed()).Fold f
+
+ and ConcatEnumerator<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) =
+ let mutable state = SeqProcessNextStates.NotStarted
+ let main = sources.GetEnumerator ()
+
+ let mutable active = EmptyEnumerators.Element
+
+ let rec moveNext () =
+ if active.MoveNext () then
+ true
+ elif main.MoveNext () then
+ active.Dispose ()
+ active <- main.Current.GetEnumerator ()
+ moveNext ()
+ else
+ state <- SeqProcessNextStates.Finished
+ false
+
+ interface IEnumerator<'T> with
+ member __.Current =
+ if state = SeqProcessNextStates.InProcess then active.Current
+ else
+ match state with
+ | SeqProcessNextStates.NotStarted -> notStarted()
+ | SeqProcessNextStates.Finished -> alreadyFinished()
+ | _ -> failwith "library implementation error: all states should have been handled"
+
+ interface IEnumerator with
+ member this.Current = box ((Upcast.enumerator this)).Current
+ member __.MoveNext () =
+ state <- SeqProcessNextStates.InProcess
+ moveNext ()
+ member __.Reset () = noReset ()
+
+ interface IDisposable with
+ member __.Dispose () =
+ main.Dispose ()
+ active.Dispose ()
+
+ and AppendEnumerable<'T> (sources:list>) =
+ inherit EnumerableBase<'T>()
+
+ interface IEnumerable<'T> with
+ member this.GetEnumerator () : IEnumerator<'T> =
+ Upcast.enumerator (new ConcatEnumerator<_,_> (sources |> List.rev))
+
+ override this.Append source =
+ Upcast.seq (AppendEnumerable (source::sources))
+
+ interface ISeq<'T> with
+ member this.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> =
+ Upcast.seq (Enumerable<'T,'V>(this, next, 1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) =
+ Fold.executeThin f (Fold.enumerable this)
+
+ and ConcatEnumerable<'T, 'Collection when 'Collection :> seq<'T>> (sources:seq<'Collection>) =
+ inherit EnumerableBase<'T>()
+
+ interface IEnumerable<'T> with
+ member this.GetEnumerator () : IEnumerator<'T> =
+ Upcast.enumerator (new ConcatEnumerator<_,_> (sources))
+
+ interface ISeq<'T> with
+ member this.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> =
+ Upcast.seq (Enumerable<'T,'V>(this, next, 1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) =
+ Fold.executeThin f (Fold.enumerable this)
+
+ let create enumerable current =
+ Upcast.seq (Enumerable (enumerable, current, 1))
+
+ module EmptyEnumerable =
+ type Enumerable<'T> () =
+ inherit Enumerable.EnumerableBase<'T>()
+
+ static let singleton = Enumerable<'T>() :> ISeq<'T>
+ static member Instance = singleton
+
+ interface IEnumerable<'T> with
+ member this.GetEnumerator () : IEnumerator<'T> = IEnumerator.Empty<'T>()
+
+ override this.Append source =
+ Upcast.seq (Enumerable.EnumerableThin<'T> source)
+
+ interface ISeq<'T> with
+ member this.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> =
+ Upcast.seq (Enumerable.Enumerable<'T,'V>(this, next, 1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) =
+ Fold.executeThin f (Fold.enumerable this)
+
+ module Array =
+ type Enumerator<'T,'U>(array:array<'T>, activity:Activity<'T,'U>, result:Result<'U>) =
+ inherit Enumerable.EnumeratorBase<'U>(result, activity)
+
+ let mutable idx = 0
+
+ let rec moveNext () =
+ if (result.HaltedIdx = 0) && idx < array.Length then
+ idx <- idx+1
+ if activity.ProcessNext array.[idx-1] then
+ true
+ else
+ moveNext ()
+ else
+ result.SeqState <- SeqProcessNextStates.Finished
+ let mutable stopTailCall = ()
+ activity.ChainComplete (&stopTailCall, result.HaltedIdx)
+ false
+
+ interface IEnumerator with
+ member __.MoveNext () =
+ result.SeqState <- SeqProcessNextStates.InProcess
+ moveNext ()
+
+ type Enumerable<'T,'U>(array:array<'T>, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) =
+ inherit Enumerable.EnumerableBase<'U>()
+
+ interface IEnumerable<'U> with
+ member this.GetEnumerator () : IEnumerator<'U> =
+ let result = Result<'U> ()
+ Upcast.enumerator (new Enumerator<'T,'U>(array, createFold transformFactory result pipeIdx, result))
+
+ interface ISeq<'U> with
+ member __.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> =
+ Upcast.seq (new Enumerable<'T,'V>(array, ComposedFactory.Combine transformFactory next, 1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) =
+ Fold.execute f transformFactory pipeIdx (Fold.Array array)
+
+ module ResizeArray =
+ type Enumerator<'T,'U>(array:ResizeArray<'T>, activity:Activity<'T,'U>, result:Result<'U>) =
+ inherit Enumerable.EnumeratorBase<'U>(result, activity)
+
+ let mutable idx = 0
+
+ let rec moveNext () =
+ if (result.HaltedIdx = 0) && idx < array.Count then
+ idx <- idx+1
+ if activity.ProcessNext array.[idx-1] then
+ true
+ else
+ moveNext ()
+ else
+ result.SeqState <- SeqProcessNextStates.Finished
+ let mutable stopTailCall = ()
+ activity.ChainComplete (&stopTailCall, result.HaltedIdx)
+ false
+
+ interface IEnumerator with
+ member __.MoveNext () =
+ result.SeqState <- SeqProcessNextStates.InProcess
+ moveNext ()
+
+ type Enumerable<'T,'U>(resizeArray:ResizeArray<'T>, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) =
+ inherit Enumerable.EnumerableBase<'U>()
+
+ interface IEnumerable<'U> with
+ member this.GetEnumerator () : IEnumerator<'U> =
+ let result = Result<'U> ()
+ Upcast.enumerator (new Enumerator<'T,'U>(resizeArray, createFold transformFactory result pipeIdx, result))
+
+ interface ISeq<'U> with
+ member __.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> =
+ Upcast.seq (new Enumerable<'T,'V>(resizeArray, ComposedFactory.Combine transformFactory next, 1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) =
+ Fold.execute f transformFactory pipeIdx (Fold.resizeArray resizeArray)
+
+ module List =
+ type Enumerator<'T,'U>(alist:list<'T>, activity:Activity<'T,'U>, result:Result<'U>) =
+ inherit Enumerable.EnumeratorBase<'U>(result, activity)
+
+ let mutable list = alist
+
+ let rec moveNext current =
+ match result.HaltedIdx, current with
+ | 0, head::tail ->
+ if activity.ProcessNext head then
+ list <- tail
+ true
+ else
+ moveNext tail
+ | _ ->
+ result.SeqState <- SeqProcessNextStates.Finished
+ let mutable stopTailCall = ()
+ activity.ChainComplete (&stopTailCall, result.HaltedIdx)
+ false
+
+ interface IEnumerator with
+ member __.MoveNext () =
+ result.SeqState <- SeqProcessNextStates.InProcess
+ moveNext list
+
+ type Enumerable<'T,'U>(alist:list<'T>, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) =
+ inherit Enumerable.EnumerableBase<'U>()
+
+ interface IEnumerable<'U> with
+ member this.GetEnumerator () : IEnumerator<'U> =
+ let result = Result<'U> ()
+ Upcast.enumerator (new Enumerator<'T,'U>(alist, createFold transformFactory result pipeIdx, result))
+
+ interface ISeq<'U> with
+ member __.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> =
+ Upcast.seq (new Enumerable<'T,'V>(alist, ComposedFactory.Combine transformFactory next, pipeIdx+1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) =
+ Fold.execute f transformFactory pipeIdx (Fold.List alist)
+
+ let create alist current =
+ Upcast.seq (Enumerable(alist, current, 1))
+
+ module Unfold =
+ type Enumerator<'T,'U,'State>(generator:'State->option<'T*'State>, state:'State, activity:Activity<'T,'U>, result:Result<'U>) =
+ inherit Enumerable.EnumeratorBase<'U>(result, activity)
+
+ let mutable current = state
+
+ let rec moveNext () =
+ match result.HaltedIdx, generator current with
+ | 0, Some (item, nextState) ->
+ current <- nextState
+ if activity.ProcessNext item then
+ true
+ else
+ moveNext ()
+ | _ -> false
+
+ interface IEnumerator with
+ member __.MoveNext () =
+ result.SeqState <- SeqProcessNextStates.InProcess
+ moveNext ()
+
+ type Enumerable<'T,'U,'GeneratorState>(generator:'GeneratorState->option<'T*'GeneratorState>, state:'GeneratorState, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) =
+ inherit Enumerable.EnumerableBase<'U>()
+
+ interface IEnumerable<'U> with
+ member this.GetEnumerator () : IEnumerator<'U> =
+ let result = Result<'U> ()
+ Upcast.enumerator (new Enumerator<'T,'U,'GeneratorState>(generator, state, createFold transformFactory result pipeIdx, result))
+
+ interface ISeq<'U> with
+ member this.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> =
+ Upcast.seq (new Enumerable<'T,'V,'GeneratorState>(generator, state, ComposedFactory.Combine transformFactory next, pipeIdx+1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'U,'Result,'State>) =
+ Fold.execute f transformFactory pipeIdx (Fold.unfold (generator, state))
+
+ module Init =
+ // The original implementation of "init" delayed the calculation of Current, and so it was possible
+ // to do MoveNext without it's value being calculated.
+ // I can imagine only two scenerios where that is possibly sane, although a simple solution is readily
+ // at hand in both cases. The first is that of an expensive generator function, where you skip the
+ // first n elements. The simple solution would have just been to have a map ((+) n) as the first operation
+ // instead. The second case would be counting elements, but that is only of use if you're not filtering
+ // or mapping or doing anything else (as that would cause Current to be evaluated!) and
+ // so you already know what the count is!! Anyway, someone thought it was a good idea, so
+ // I have had to add an extra function that is used in Skip to determine if we are touching
+ // Current or not.
+
+ let getTerminatingIdx (count:Nullable) =
+ // we are offset by 1 to allow for values going up to System.Int32.MaxValue
+ // System.Int32.MaxValue is an illegal value for the "infinite" sequence
+ if count.HasValue then
+ count.Value - 1
+ else
+ System.Int32.MaxValue
+
+ type Enumerator<'T,'U>(count:Nullable, f:int->'T, activity:Activity<'T,'U>, result:Result<'U>) =
+ inherit Enumerable.EnumeratorBase<'U>(result, activity)
+
+ let isSkipping =
+ match box activity with
+ | :? ISkipable as skip -> skip.CanSkip
+ | _ -> fun () -> false
+
+ let terminatingIdx =
+ getTerminatingIdx count
+
+ let mutable maybeSkipping = true
+ let mutable idx = -1
+
+ let rec moveNext () =
+ if result.HaltedIdx = 0 && idx < terminatingIdx then
+ idx <- idx + 1
+
+ if maybeSkipping then
+ // Skip can only is only checked at the start of the sequence, so once
+ // triggered, we stay triggered.
+ maybeSkipping <- isSkipping ()
+
+ if maybeSkipping then
+ moveNext ()
+ elif activity.ProcessNext (f idx) then
+ true
+ else
+ moveNext ()
+ elif result.HaltedIdx = 0 && idx = System.Int32.MaxValue then
+ raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue))
+ else
+ result.SeqState <- SeqProcessNextStates.Finished
+ let mutable stopTailCall = ()
+ activity.ChainComplete (&stopTailCall, result.HaltedIdx)
+ false
+
+ interface IEnumerator with
+ member __.MoveNext () =
+ result.SeqState <- SeqProcessNextStates.InProcess
+ moveNext ()
+
+ type Enumerable<'T,'U>(count:Nullable, f:int->'T, transformFactory:TransformFactory<'T,'U>, pipeIdx:PipeIdx) =
+ inherit Enumerable.EnumerableBase<'U>()
+
+ interface IEnumerable<'U> with
+ member this.GetEnumerator () : IEnumerator<'U> =
+ let result = Result<'U> ()
+ Upcast.enumerator (new Enumerator<'T,'U>(count, f, createFold transformFactory result pipeIdx, result))
+
+ interface ISeq<'U> with
+ member this.PushTransform (next:TransformFactory<'U,'V>) : ISeq<'V> =
+ Upcast.seq (new Enumerable<'T,'V>(count, f, ComposedFactory.Combine transformFactory next, pipeIdx+1))
+
+ member this.Fold<'Result,'State> (createResult:PipeIdx->Folder<'U,'Result,'State>) =
+ let terminatingIdx = getTerminatingIdx count
+ Fold.execute createResult transformFactory pipeIdx (Fold.init (f, terminatingIdx))
+
+ let upto lastOption f =
+ match lastOption with
+ | Some b when b<0 -> failwith "library implementation error: upto can never be called with a negative value"
+ | _ ->
+ let unstarted = -1 // index value means unstarted (and no valid index)
+ let completed = -2 // index value means completed (and no valid index)
+ let unreachable = -3 // index is unreachable from 0,1,2,3,...
+ let finalIndex = match lastOption with
+ | Some b -> b // here b>=0, a valid end value.
+ | None -> unreachable // run "forever", well as far as Int32.MaxValue since indexing with a bounded type.
+ // The Current value for a valid index is "f i".
+ // Lazy<_> values are used as caches, to store either the result or an exception if thrown.
+ // These "Lazy<_>" caches are created only on the first call to current and forced immediately.
+ // The lazy creation of the cache nodes means enumerations that skip many Current values are not delayed by GC.
+ // For example, the full enumeration of Seq.initInfinite in the tests.
+ // state
+ let index = ref unstarted
+ // a Lazy node to cache the result/exception
+ let current = ref (Unchecked.defaultof<_>)
+ let setIndex i = index := i; current := (Unchecked.defaultof<_>) // cache node unprimed, initialised on demand.
+ let getCurrent() =
+ if !index = unstarted then notStarted()
+ if !index = completed then alreadyFinished()
+ match box !current with
+ | null -> current := Lazy<_>.Create(fun () -> f !index)
+ | _ -> ()
+ // forced or re-forced immediately.
+ (!current).Force()
+ { new IEnumerator<'U> with
+ member x.Current = getCurrent()
+ interface IEnumerator with
+ member x.Current = box (getCurrent())
+ member x.MoveNext() =
+ if !index = completed then
+ false
+ elif !index = unstarted then
+ setIndex 0
+ true
+ else (
+ if !index = System.Int32.MaxValue then raise <| System.InvalidOperationException (SR.GetString(SR.enumerationPastIntMaxValue))
+ if !index = finalIndex then
+ false
+ else
+ setIndex (!index + 1)
+ true
+ )
+ member this.Reset() = noReset()
+ interface System.IDisposable with
+ member x.Dispose () = () }
+
+ type EnumerableDecider<'T>(count:Nullable, f:int->'T, pipeIdx:PipeIdx) =
+ inherit Enumerable.EnumerableBase<'T>()
+
+ interface IEnumerable<'T> with
+ member this.GetEnumerator () : IEnumerator<'T> =
+ // we defer back to the original implementation as, as it's quite idiomatic in it's decision
+ // to calculate Current in a lazy fashion. I doubt anyone is really using this functionality
+ // in the way presented, but it's possible.
+ upto (if count.HasValue then Some (count.Value-1) else None) f
+
+ interface ISeq<'T> with
+ member this.PushTransform (next:TransformFactory<'T,'U>) : ISeq<'U> =
+ Upcast.seq (Enumerable<'T,'V>(count, f, next, pipeIdx+1))
+
+ member this.Fold<'Result,'State> (f:PipeIdx->Folder<'T,'Result,'State>) =
+ Fold.executeThin f (Fold.enumerable (Upcast.enumerable this))
+
+ []
+ let ofResizeArrayUnchecked (source:ResizeArray<'T>) : ISeq<'T> =
+ Upcast.seq (ResizeArray.Enumerable (source, IdentityFactory.Instance, 1))
+
+ []
+ let ofArray (source:array<'T>) : ISeq<'T> =
+ Upcast.seq (Array.Enumerable (source, IdentityFactory.Instance, 1))
+
+ []
+ let ofList (source:list<'T>) : ISeq<'T> =
+ Upcast.seq (List.Enumerable (source, IdentityFactory.Instance, 1))
+
+ []
+ let ofSeq (source:seq<'T>) : ISeq<'T> =
+ match source with
+ | :? ISeq<'T> as seq -> seq
+ | :? array<'T> as array -> ofArray array
+ | :? list<'T> as list -> ofList list
+ | null -> nullArg "source"
+ | _ -> Upcast.seq (Enumerable.EnumerableThin<'T> source)
+
+ []
+ let inline average (source:ISeq<'T>) =
+ source.Fold (fun _ ->
+ upcast { new FolderWithPostProcessing<'T,'T,int> (LanguagePrimitives.GenericZero, 0) with
+ override this.ProcessNext value =
+ this.Result <- Checked.(+) this.Result value
+ this.State <- this.State + 1
+ Unchecked.defaultof<_> (* return value unused in Fold context *)
+
+ override this.OnComplete _ =
+ if this.State = 0 then
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ this.Result <- LanguagePrimitives.DivideByInt<'T> this.Result this.State
+ override this.OnDispose () = () })
+
+ []
+ let inline averageBy (f:'T->'U) (source:ISeq<'T>) =
+ source.Fold (fun _ ->
+ upcast { new FolderWithPostProcessing<'T,'U,int>(LanguagePrimitives.GenericZero,0) with
+ override this.ProcessNext value =
+ this.Result <- Checked.(+) this.Result (f value)
+ this.State <- this.State + 1
+ Unchecked.defaultof<_> (* return value unused in Fold context *)
+
+ override this.OnComplete _ =
+ if this.State = 0 then
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ this.Result <- LanguagePrimitives.DivideByInt<'U> this.Result this.State
+ override this.OnDispose () = () })
+
+ []
+ let empty<'T> = EmptyEnumerable.Enumerable<'T>.Instance
+
+ []
+ let exactlyOne (source:ISeq<'T>) : 'T =
+ source.Fold (fun pipeIdx ->
+ upcast { new FolderWithPostProcessing<'T,'T,Values>(Unchecked.defaultof<'T>, Values(true, false)) with
+ override this.ProcessNext value =
+ if this.State._1 then
+ this.State._1 <- false
+ this.Result <- value
+ else
+ this.State._2 <- true
+ this.StopFurtherProcessing pipeIdx
+ Unchecked.defaultof<_> (* return value unused in Fold context *)
+
+ override this.OnComplete _ =
+ if this.State._1 then
+ invalidArg "source" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
+ elif this.State._2 then
+ invalidArg "source" (SR.GetString SR.inputSequenceTooLong)
+ override this.OnDispose () = () })
+
+ []
+ let inline fold<'T,'State> (f:'State->'T->'State) (seed:'State) (source:ISeq<'T>) : 'State =
+ source.Fold (fun _ ->
+ upcast { new Folder<'T,'State,NoValue>(seed,Unchecked.defaultof) with
+ override this.ProcessNext value =
+ this.Result <- f this.Result value
+ Unchecked.defaultof<_> (* return value unused in Fold context *) })
+
+ []
+ let inline fold2<'T1,'T2,'State> (folder:'State->'T1->'T2->'State) (state:'State) (source1:ISeq<'T1>) (source2: ISeq<'T2>) =
+ source1.Fold (fun pipeIdx ->
+ upcast { new FolderWithPostProcessing<_,'State,IEnumerator<'T2>>(state,source2.GetEnumerator()) with
+ override this.ProcessNext value =
+ if this.State.MoveNext() then
+ this.Result <- folder this.Result value this.State.Current
+ else
+ this.StopFurtherProcessing pipeIdx
+ Unchecked.defaultof<_> (* return value unused in Fold context *)
+
+ override this.OnComplete _ = ()
+ override this.OnDispose () = this.State.Dispose () })
+
+ []
+ let unfold (generator:'State->option<'T * 'State>) (state:'State) : ISeq<'T> =
+ Upcast.seq (new Unfold.Enumerable<'T,'T,'State>(generator, state, IdentityFactory.Instance, 1))
+
+ []
+ let initInfinite<'T> (f:int->'T) : ISeq<'T> =
+ Upcast.seq (new Init.EnumerableDecider<'T>(Nullable (), f, 1))
+
+ []
+ let init<'T> (count:int) (f:int->'T) : ISeq<'T> =
+ if count < 0 then invalidArgInputMustBeNonNegative "count" count
+ elif count = 0 then empty else
+ Upcast.seq (new Init.EnumerableDecider<'T>(Nullable count, f, 1))
+
+ []
+ let inline iter f (source:ISeq<'T>) =
+ source.Fold (fun _ ->
+ upcast { new Folder<'T,unit,NoValue> ((),Unchecked.defaultof) with
+ override this.ProcessNext value =
+ f value
+ Unchecked.defaultof<_> (* return value unused in Fold context *) })
+
+ []
+ let inline iter2 (f:'T->'U->unit) (source1:ISeq<'T>) (source2:ISeq<'U>) : unit =
+ source1.Fold (fun pipeIdx ->
+ upcast { new FolderWithPostProcessing<'T,unit,IEnumerator<'U>> ((),source2.GetEnumerator()) with
+ override this.ProcessNext value =
+ if this.State.MoveNext() then
+ f value this.State.Current
+ else
+ this.StopFurtherProcessing pipeIdx
+ Unchecked.defaultof<_> (* return value unused in Fold context *)
+
+ override this.OnComplete _ = ()
+ override this.OnDispose () = this.State.Dispose () })
+
+ []
+ let inline iteri2 (f:int->'T->'U->unit) (source1:ISeq<'T>) (source2:ISeq<'U>) : unit =
+ source1.Fold (fun pipeIdx ->
+ upcast { new FolderWithPostProcessing<'T,unit,Values>>((),Values<_,_>(-1,source2.GetEnumerator())) with
+ override this.ProcessNext value =
+ if this.State._2.MoveNext() then
+ f this.State._1 value this.State._2.Current
+ this.State._1 <- this.State._1 + 1
+ Unchecked.defaultof<_>
+ else
+ this.StopFurtherProcessing pipeIdx
+ Unchecked.defaultof<_>
+ override this.OnComplete _ = ()
+ override this.OnDispose () = this.State._2.Dispose () })
+
+ []
+ let tryHead (source:ISeq<'T>) =
+ source.Fold (fun pipeIdx ->
+ upcast { new Folder<'T, Option<'T>,NoValue> (None,Unchecked.defaultof) with
+ override this.ProcessNext value =
+ this.Result <- Some value
+ this.StopFurtherProcessing pipeIdx
+ Unchecked.defaultof<_> (* return value unused in Fold context *) })
+
+ [