29 people like it.
Like the snippet!
Enumerator computation builder
The snippet defines computation builder for working with IEnumerator. The bind operation (let!) reads next element from the enumerator, so the computation can be used for expressing things that cannot be written just using seq.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
|
module Enumerator =
let single a =
let state = ref 0
{ new IEnumerator<_> with
member self.Current = if (state.Value = 1) then a else invalidOp "!"
interface System.Collections.IEnumerator with
member self.Current = if (state.Value = 1) then box a else invalidOp "!"
member self.MoveNext() = state := state.Value + 1; state.Value = 1
member self.Reset() = state := 0
interface System.IDisposable with
member self.Dispose() = ()}
let combine (a:IEnumerator<_>) b =
let current = ref a
let first = ref true
{ new IEnumerator<_> with
member self.Current = current.Value.Current
interface System.Collections.IEnumerator with
member self.Current = box current.Value.Current
member self.MoveNext() =
if current.Value.MoveNext() then true
elif first.Value then
current := b
first := false
current.Value.MoveNext()
else false
member self.Reset() =
a.Reset(); b.Reset()
first := true; current := a
interface System.IDisposable with
member self.Dispose() = a.Dispose(); b.Dispose() }
let zero () =
{ new IEnumerator<_> with
member self.Current = invalidOp "!"
interface System.Collections.IEnumerator with
member self.Current = invalidOp "!"
member self.MoveNext() = false
member self.Reset() = ()
interface System.IDisposable with
member self.Dispose() = ()}
let delay f =
let en : Lazy<IEnumerator<_>> = lazy f()
{ new IEnumerator<_> with
member self.Current = en.Value.Current
interface System.Collections.IEnumerator with
member self.Current = box en.Value.Current
member self.MoveNext() = en.Value.MoveNext()
member self.Reset() = en.Value.Reset()
interface System.IDisposable with
member self.Dispose() = en.Value.Dispose() }
let toSeq gen =
{ new IEnumerable<'T> with
member x.GetEnumerator() = gen()
interface IEnumerable with
member x.GetEnumerator() = (gen() :> IEnumerator) }
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
|
type EnumerableBuilder() =
member x.Delay(f) = Enumerator.delay f
member x.YieldFrom(a) = a
member x.Yield(a) = Enumerator.single a
member x.Bind(a:IEnumerator<'a>, f:_ -> IEnumerator<'b>) =
if (a.MoveNext()) then f (Some(a.Current)) else f(None)
member x.Combine(a, b) = Enumerator.combine a b
member x.Zero() = Enumerator.zero ()
let iter = new EnumerableBuilder()
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
|
// Enumerator that produces 3 numbers
let e = iter { yield 1; yield 2; yield 3 }
e.MoveNext()
e.Current
// Enumerator that iumplements "identity" and prints elements
let rec loop e = iter {
let! v = e
printfn "%A" v
yield v
yield! loop e }
let e2 = iter { yield 1; yield 2; yield 3 }
let r = loop e2
r.MoveNext()
r.Current
// Implementing the zip function for enumerators
let rec zipE xs ys = iter {
let! x = xs
let! y = ys
match x, y with
| Some(x), Some(y) ->
yield x, y
yield! zipE xs ys
| _ -> () }
// Implementing zip for sequences using zip for enumerators
let zip (a:seq<_>) (b:seq<_>) =
Enumerator.toSeq (fun () ->
zipE (a.GetEnumerator()) (b.GetEnumerator()))
zip [1;2;3] ["a";"b";"c"]
zip [1;2;3;4] ["a";"b";"c"]
|
Multiple items
val single : a:'a -> IEnumerator<'a>
Full name: Script.Enumerator.single
--------------------
type single = System.Single
Full name: Microsoft.FSharp.Core.single
val a : 'a
val state : int ref
Multiple items
val ref : value:'T -> 'T ref
Full name: Microsoft.FSharp.Core.Operators.ref
--------------------
type 'T ref = Ref<'T>
Full name: Microsoft.FSharp.Core.ref<_>
Multiple items
type IEnumerator =
member Current : obj
member MoveNext : unit -> bool
member Reset : unit -> unit
Full name: System.Collections.IEnumerator
--------------------
type IEnumerator<'T> =
member Current : 'T
Full name: System.Collections.Generic.IEnumerator<_>
val self : IEnumerator<'a>
property IEnumerator.Current: 'a
property Ref.Value: int
val invalidOp : message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.invalidOp
namespace System
namespace System.Collections
type IEnumerator =
member Current : obj
member MoveNext : unit -> bool
member Reset : unit -> unit
Full name: System.Collections.IEnumerator
val self : IEnumerator
property IEnumerator.Current: obj
val box : value:'T -> obj
Full name: Microsoft.FSharp.Core.Operators.box
IEnumerator.MoveNext() : bool
IEnumerator.Reset() : unit
type IDisposable =
member Dispose : unit -> unit
Full name: System.IDisposable
val self : System.IDisposable
System.IDisposable.Dispose() : unit
val combine : a:IEnumerator<'a> -> b:IEnumerator<'a> -> IEnumerator<'a>
Full name: Script.Enumerator.combine
val a : IEnumerator<'a>
val b : IEnumerator<'a>
val current : IEnumerator<'a> ref
val first : bool ref
property Ref.Value: IEnumerator<'a>
property Ref.Value: bool
val zero : unit -> IEnumerator<'a>
Full name: Script.Enumerator.zero
val delay : f:(unit -> IEnumerator<'a>) -> IEnumerator<'a>
Full name: Script.Enumerator.delay
val f : (unit -> IEnumerator<'a>)
val en : Lazy<IEnumerator<'a>>
Multiple items
active recognizer Lazy: Lazy<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.( |Lazy| )
--------------------
type Lazy<'T> = System.Lazy<'T>
Full name: Microsoft.FSharp.Control.Lazy<_>
property System.Lazy.Value: IEnumerator<'a>
val toSeq : gen:(unit -> IEnumerator<'T>) -> IEnumerable<'T>
Full name: Script.Enumerator.toSeq
val gen : (unit -> IEnumerator<'T>)
Multiple items
type IEnumerable =
member GetEnumerator : unit -> IEnumerator
Full name: System.Collections.IEnumerable
--------------------
type IEnumerable<'T> =
member GetEnumerator : unit -> IEnumerator<'T>
Full name: System.Collections.Generic.IEnumerable<_>
val x : IEnumerable<'T>
IEnumerable.GetEnumerator() : IEnumerator<'T>
val x : IEnumerable
IEnumerable.GetEnumerator() : IEnumerator
Multiple items
type EnumerableBuilder =
new : unit -> EnumerableBuilder
member Bind : a:IEnumerator<'a> * f:('a option -> IEnumerator<'b>) -> IEnumerator<'b>
member Combine : a:IEnumerator<'b> * b:IEnumerator<'b> -> IEnumerator<'b>
member Delay : f:(unit -> IEnumerator<'e>) -> IEnumerator<'e>
member Yield : a:'c -> IEnumerator<'c>
member YieldFrom : a:'d -> 'd
member Zero : unit -> IEnumerator<'a>
Full name: Script.EnumerableBuilder
--------------------
new : unit -> EnumerableBuilder
val x : EnumerableBuilder
member EnumerableBuilder.Delay : f:(unit -> IEnumerator<'e>) -> IEnumerator<'e>
Full name: Script.EnumerableBuilder.Delay
val f : (unit -> IEnumerator<'e>)
module Enumerator
from Script
member EnumerableBuilder.YieldFrom : a:'d -> 'd
Full name: Script.EnumerableBuilder.YieldFrom
val a : 'd
member EnumerableBuilder.Yield : a:'c -> IEnumerator<'c>
Full name: Script.EnumerableBuilder.Yield
val a : 'c
val single : a:'a -> IEnumerator<'a>
Full name: Script.Enumerator.single
member EnumerableBuilder.Bind : a:IEnumerator<'a> * f:('a option -> IEnumerator<'b>) -> IEnumerator<'b>
Full name: Script.EnumerableBuilder.Bind
val f : ('a option -> IEnumerator<'b>)
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
member EnumerableBuilder.Combine : a:IEnumerator<'b> * b:IEnumerator<'b> -> IEnumerator<'b>
Full name: Script.EnumerableBuilder.Combine
val a : IEnumerator<'b>
val b : IEnumerator<'b>
member EnumerableBuilder.Zero : unit -> IEnumerator<'a>
Full name: Script.EnumerableBuilder.Zero
val iter : EnumerableBuilder
Full name: Script.iter
val e : IEnumerator<int>
Full name: Script.e
property IEnumerator.Current: int
val loop : e:IEnumerator<'a> -> IEnumerator<'a option>
Full name: Script.loop
val e : IEnumerator<'a>
val v : 'a option
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val e2 : IEnumerator<int>
Full name: Script.e2
val r : IEnumerator<int option>
Full name: Script.r
property IEnumerator.Current: int option
val zipE : xs:IEnumerator<'a> -> ys:IEnumerator<'b> -> IEnumerator<'a * 'b>
Full name: Script.zipE
val xs : IEnumerator<'a>
val ys : IEnumerator<'b>
val x : 'a option
val y : 'b option
val x : 'a
val y : 'b
val zip : a:seq<'a> -> b:seq<'b> -> IEnumerable<'a * 'b>
Full name: Script.zip
val a : seq<'a>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
val b : seq<'b>
IEnumerable.GetEnumerator() : IEnumerator<'a>
IEnumerable.GetEnumerator() : IEnumerator<'b>
More information