Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor to add toSeq in Option module #1

Open
wants to merge 1 commit into
base: RFC-FS-1007
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,16 @@ type OptionModule() =
member this.MapBindEquivalenceProperties () =
let fn x = x + 3
Assert.AreEqual(Option.map fn None, Option.bind (fn >> Some) None)
Assert.AreEqual(Option.map fn (Some 5), Option.bind (fn >> Some) (Some 5))
Assert.AreEqual(Option.map fn (Some 5), Option.bind (fn >> Some) (Some 5))

[<Test>]
member this.ToSeq() =
Assert.IsFalse(Some 5 |> Option.toSeq |> Seq.isEmpty)
Assert.AreEqual(Some 5 |> Option.toSeq |> Seq.length, 1)
Assert.AreEqual(Some 5 |> Option.toSeq |> Seq.tryHead, Some 5)
Assert.IsFalse(Some "" |> Option.toSeq |> Seq.isEmpty)
Assert.AreEqual(Some "" |> Option.toSeq |> Seq.length, 1)
Assert.AreEqual(Some "" |> Option.toSeq |> Seq.tryHead, Some "")
Assert.IsTrue(None |> Option.toSeq |> Seq.isEmpty)
Assert.AreEqual(None |> Option.toSeq |> Seq.length, 0)
Assert.AreEqual(None |> Option.toSeq |> Seq.tryHead, None)
1 change: 1 addition & 0 deletions src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2732,6 +2732,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T)
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.String ToString()
Microsoft.FSharp.Core.OptionModule: System.Type GetType()
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2766,6 +2766,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T)
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.String ToString()
Microsoft.FSharp.Core.OptionModule: System.Type GetType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2737,6 +2737,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T)
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.String ToString()
Microsoft.FSharp.Core.OptionModule: System.Type GetType()
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2738,6 +2738,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T)
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.String ToString()
Microsoft.FSharp.Core.OptionModule: System.Type GetType()
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2750,6 +2750,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T)
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.String ToString()
Microsoft.FSharp.Core.OptionModule: System.Type GetType()
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2737,6 +2737,7 @@ Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfNu
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OfObj[T](T)
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElseWith[T](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.FSharpOption`1[T]], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[T] OrElse[T](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Collections.Generic.IEnumerable`1[T] ToSeq[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.Nullable`1[T] ToNullable[T](Microsoft.FSharp.Core.FSharpOption`1[T])
Microsoft.FSharp.Core.OptionModule: System.String ToString()
Microsoft.FSharp.Core.OptionModule: System.Type GetType()
Expand Down
56 changes: 56 additions & 0 deletions src/fsharp/FSharp.Core/local.fs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,62 @@ open Microsoft.FSharp.Core.ICloneableExtensions
#else
#endif

module internal 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 mkSeq f =
{ new IEnumerable<'U> with
member x.GetEnumerator() = f()
interface System.Collections.IEnumerable with
member x.GetEnumerator() = (f() :> System.Collections.IEnumerator) }

/// A concrete implementation of an enumerator that returns no values
[<Sealed>]
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>)

[<NoEquality; NoComparison>]
type EmptyEnumerable<'T> =
| EmptyEnumerable
interface IEnumerable<'T> with
member x.GetEnumerator() = empty<'T>()
interface System.Collections.IEnumerable with
member x.GetEnumerator() = (empty<'T>() :> System.Collections.IEnumerator)

[<Sealed>]
type Singleton<'T>(v:'T) =
let mutable started = false
interface IEnumerator<'T> with
member x.Current = v
interface System.Collections.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>


module internal List =

Expand Down
19 changes: 18 additions & 1 deletion src/fsharp/FSharp.Core/local.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,28 @@ module internal DetailedExceptions =
val invalidArg3ArraysDifferent: arg1:string -> arg2:string -> arg3:string -> len1:int -> len2:int -> len3:int -> _

/// Definitions internal for this library.
namespace Microsoft.FSharp.Primitives.Basics
namespace Microsoft.FSharp.Primitives.Basics

open Microsoft.FSharp.Core
open Microsoft.FSharp.Collections

module internal IEnumerator =
val noReset : unit -> 'T
val notStarted : unit -> 'T
val alreadyFinished : unit -> 'T
val check : bool -> unit
val mkSeq : (unit -> System.Collections.Generic.IEnumerator<'T>) -> System.Collections.Generic.IEnumerable<'T>

[<NoEquality; NoComparison>]
type EmptyEnumerable<'T> =
| EmptyEnumerable
interface System.Collections.Generic.IEnumerable<'T>
interface System.Collections.IEnumerable

val Empty : unit -> System.Collections.Generic.IEnumerator<'T>
val Singleton : 'T -> System.Collections.Generic.IEnumerator<'T>


module internal List =
val allPairs : 'T1 list -> 'T2 list -> ('T1 * 'T2) list
val choose: ('T -> 'U option) -> 'T list -> 'U list
Expand Down
4 changes: 4 additions & 0 deletions src/fsharp/FSharp.Core/option.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Microsoft.FSharp.Core

open Microsoft.FSharp.Primitives.Basics
open Microsoft.FSharp.Core.Operators

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
Expand Down Expand Up @@ -79,6 +80,9 @@ namespace Microsoft.FSharp.Core
[<CompiledName("ToList")>]
let toList option = match option with None -> [ ] | Some x -> [ x ]

[<CompiledName("ToSeq")>]
let toSeq option = match option with Some x -> IEnumerator.mkSeq (fun () -> IEnumerator.Singleton x) | None -> upcast IEnumerator.EmptyEnumerable

[<CompiledName("ToNullable")>]
let toNullable option = match option with None -> System.Nullable() | Some v -> System.Nullable(v)

Expand Down
5 changes: 5 additions & 0 deletions src/fsharp/FSharp.Core/option.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,11 @@ namespace Microsoft.FSharp.Core
[<CompiledName("ToList")>]
val toList: option:'T option -> 'T list

/// <summary>Convert the option to a sequence of length 0 or 1.</summary>
/// <param name="option">The input option.</param>
/// <returns>The result sequence.</returns>
[<CompiledName("ToSeq")>]
val toSeq: option: 'T option -> seq<'T>

/// <summary>Convert the option to a Nullable value.</summary>
/// <param name="option">The input option.</param>
Expand Down
68 changes: 9 additions & 59 deletions src/fsharp/FSharp.Core/seq.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ namespace Microsoft.FSharp.Collections

module IEnumerator =

open Microsoft.FSharp.Primitives.Basics.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> =
Expand All @@ -35,28 +32,6 @@ namespace Microsoft.FSharp.Collections
| :? System.IDisposable as e -> e.Dispose()
| _ -> () }

/// A concrete implementation of an enumerator that returns no values
[<Sealed>]
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)
Expand Down Expand Up @@ -352,20 +327,6 @@ namespace Microsoft.FSharp.Collections

let ofArray arr = (new ArrayEnumerator<'T>(arr) :> IEnumerator<'T>)

[<Sealed>]
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
Expand All @@ -385,6 +346,7 @@ namespace Microsoft.FSharp.Collections
//
module Generator =

open Microsoft.FSharp.Primitives.Basics
open System.Collections
open System.Collections.Generic

Expand Down Expand Up @@ -554,22 +516,8 @@ namespace Microsoft.FSharp.Core.CompilerServices
| null -> nullArg argName
| _ -> ()

let mkSeq f =
{ new IEnumerable<'U> with
member x.GetEnumerator() = f()
interface IEnumerable with
member x.GetEnumerator() = (f() :> IEnumerator) }

[<NoEquality; NoComparison>]
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)
IEnumerator.mkSeq (fun () -> IEnumerator.generateWhileSome openf compute closef)

let GenerateUsing (openf : unit -> ('U :> System.IDisposable)) compute =
Generate openf compute (fun (s:'U) -> s.Dispose())
Expand Down Expand Up @@ -684,7 +632,7 @@ namespace Microsoft.FSharp.Core.CompilerServices
let ie = outerEnum.Current
// Optimization to detect the statically-allocated empty IEnumerables
match box ie with
| :? EmptyEnumerable<'T> ->
| :? IEnumerator.EmptyEnumerable<'T> ->
// This one is empty, just skip, don't call GetEnumerator, try again
takeOuter()
| _ ->
Expand Down Expand Up @@ -712,7 +660,7 @@ namespace Microsoft.FSharp.Core.CompilerServices
(fun () -> rest resource :> seq<_>)) :> seq<_>)

let mkConcatSeq (sources: seq<'U :> seq<'T>>) =
mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>)
IEnumerator.mkSeq (fun () -> new ConcatEnumerator<_,_>(sources) :> IEnumerator<'T>)

let EnumerateWhile (g : unit -> bool) (b: seq<'T>) : seq<'T> =
let started = ref false
Expand All @@ -724,7 +672,7 @@ namespace Microsoft.FSharp.Core.CompilerServices

let finish() = (curr := None)
mkConcatSeq
(mkSeq (fun () ->
(IEnumerator.mkSeq (fun () ->
{ new IEnumerator<_> with
member x.Current = getCurr()
interface IEnumerator with
Expand Down Expand Up @@ -843,6 +791,8 @@ namespace Microsoft.FSharp.Collections
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Seq =

open Microsoft.FSharp.Primitives.Basics.IEnumerator

#if FX_NO_ICLONEABLE
open Microsoft.FSharp.Core.ICloneableExtensions
#else
Expand Down Expand Up @@ -1238,7 +1188,7 @@ namespace Microsoft.FSharp.Collections
foldArraySubRight f arr 0 (len - 2) arr.[len - 1]

[<CompiledName("Singleton")>]
let singleton x = mkSeq (fun () -> IEnumerator.Singleton x)
let singleton x = mkSeq (fun () -> Singleton x)


[<CompiledName("Truncate")>]
Expand Down