8 people like it.
Like the snippet!
Iteratee
An iteratee based on https://john-millikin.com/software/enumerator/ and http://okmij.org/ftp/Haskell/Iteratee/IterateeIO-talk-notes.pdf
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:
|
type Stream<'el> =
| Chunk of 'el
| Empty
| EOF
type Iteratee<'el,'acc> =
| Continue of exn option * (Stream<'el> -> Iteratee<'el,'acc> * Stream<'el>)
| Yield of 'acc
type Enumerator<'el,'acc> = Iteratee<'el,'acc> -> Iteratee<'el,'acc>
type Enumeratee<'elo,'eli,'acc> = Iteratee<'eli,'acc> -> Iteratee<'elo,Iteratee<'eli,'acc>>
let runIteratee m =
match m with
| Yield x -> x
| Continue (Some e, _) -> raise e
| Continue (_, k) ->
match fst (k EOF) with
| Yield xx -> xx
| Continue _ -> failwith "Diverging iteratee"
let rec bind m f =
match m with
| Yield x -> f x
| Continue (e, k) ->
Continue(e, fun s ->
match k s with
| Yield x, s' ->
match f x with
| Continue (None, k) -> k s'
| i -> i,s'
| m', s' -> bind m' f, s')
type IterateeBuilder() =
member this.Return(x) = Yield x
member this.ReturnFrom(m:Iteratee<_,_>) = m
member this.Bind(m, k) = bind m k
member this.Zero() = Yield ()
member this.Combine(comp1, comp2) = bind comp1 (fun () -> comp2)
member this.Delay(f) = bind (Yield()) f
let iteratee = IterateeBuilder()
|
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:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
|
open System
open System.Linq
open FSharp.Monad.Iteratee
open FSharp.Monad.Iteratee.Operators
open NUnit.Framework
open FsUnit
module List =
let split p l =
let n = List.tryFindIndex p l
match n with
| Some x -> (Seq.take x l |> List.ofSeq, Seq.skip x l |> List.ofSeq)
| _ -> (l,[])
//val enumerate : 'a list -> Enumerator<'a,'b,'c>
let rec enumerate input i =
match input, i with
| [] , Continue(e,k) -> enumerate [] (fst (k EOF)) // generate a Yield or Error
| x::xs, Continue(e,k) -> enumerate xs (fst (k (Chunk x))) // generate a Continue or Error
| _ , i -> i // return the Yield or Error
// val enumeratePure1Chunk : 'a -> Enumerator<'a,'b,'c>
let enumeratePure1Chunk str i =
match str, i with
| str, Continue(None, k) -> fst (k (Chunk str))
| _ , i -> i
// val enumeratePure1Chunk : #seq<'a> -> int -> Enumerator<'a,'b,'c>
let rec enumeratePureNChunk (str:#seq<_>) n i =
match str, n, i with
| str, n, Continue(None, k) ->
let (s1, s2) = (Seq.take n str, Seq.skip n str)
enumeratePureNChunk s2 n (fst (k (Chunk str)))
| _ , _, i -> i
let counter<'a> : Iteratee<'a,int> =
let rec step n = function
| Chunk x as s -> Continue(None, step (n + 1)), s
| Empty as s -> Continue(None, step n), s
| EOF as s -> Yield n, s
Continue(None, step 0)
[<Test>]
let ``test counter should calculate the length of the list without modification``() =
let actual = enumerate [1;2;3] counter
runIteratee actual |> should equal 3
let rec peek =
let rec step = function
| Empty as s -> peek, s
| Chunk x as s -> Yield (Some x), s
| s -> Yield None, s
Continue(None, step)
let testPeek = [|
[| box ([]:char list); box None |]
[| box ['c']; box (Some 'c') |]
[| box ['c';'h';'a';'r']; box (Some 'c') |]
|]
[<Test>]
[<TestCaseSource("testPeek")>]
let ``test peek should return the value without removing it from the stream``(input:char list, expected:char option) =
let actual = enumerate input peek
runIteratee actual |> should equal expected
let rec head =
let rec step = function
| Empty as s -> head, Stream.Empty
| Chunk(x::xs) as s -> Yield x, (Chunk xs)
| s -> Continue (Some (Exception("EOF")), step), s
Continue(None, step)
let testHead = [|
[| box ['c']; box 'c' |]
[| box ['c';'h';'a';'r']; box 'c' |]
|]
[<Test>]
[<TestCaseSource("testHead")>]
let ``test head should return the value and remove it from the stream``(input:char list, expected:char) =
let actual = enumerate [input] head
runIteratee actual |> should equal expected
[<Ignore>]
[<Test>]
let ``test head should fail for an empty list``() =
enumeratePure1Chunk [] head |> runIteratee |> should throw typeof<System.Exception>
let rec drop n =
let rec step = function
| Chunk x as s -> drop (n - 1), s
| Empty as s -> Continue(None, step), s
| EOF as s -> Yield (), s
if n = 0 then Yield () else Continue(None, step)
let split (pred:char -> bool) =
let ieContM k = Continue(None, k), Stream.Empty
let rec step before = function
| Empty -> ieContM (step before)
| Chunk str ->
match List.split pred str with
| (_,[]) -> ieContM (step (before @ str))
| (str,tail) -> Yield (before @ str), Chunk tail
| s -> Yield before, s
Continue(None, step [])
[<Test>]
let ``test split should correctly split the input``() =
enumeratePure1Chunk (List.ofSeq "abcde") (split ((=) 'c')) |> runIteratee |> should equal ['a';'b']
let heads str =
let rec loop count str =
match count, str with
| (count, []) -> Yield count
| (count, str) -> Continue(None, step count str)
and step count str s =
let str = List.ofSeq str
match count, str, s with
| count, str, (Chunk []) -> loop count str, (Chunk [])
| count, c::t, (Chunk (c'::t')) ->
if c = c' then step (count + 1) t (Chunk t')
else Yield count, (Chunk (c'::t'))
| count, _, s -> Yield count, s
loop 0 str
[<Test>]
let ``test heads should count the number of characters in a set of headers``() =
enumeratePure1Chunk (List.ofSeq "abd") (heads (List.ofSeq "abc")) |> runIteratee |> should equal 2
let readLines =
let toString chars = String(Array.ofList chars)
let terminators = heads ['\r';'\n'] >>= (fun n -> if n = 0 then heads ['\n'] else Yield n)
let rec lines acc =
split (fun c -> c = '\r' || c = '\n') >>= fun l -> terminators >>= check acc l
and check acc l count =
match acc, l, count with
| acc, _, 0 -> Yield (Choice1Of2 (List.rev acc |> List.map toString))
| acc, [], _ -> Yield (Choice2Of2 (List.rev acc |> List.map toString))
| acc, l, _ -> lines (l::acc)
lines []
|
type Stream<'el> =
| Chunk of 'el
| Empty
| EOF
Full name: FSharp.Monad.Iteratee.Stream<_>
union case Stream.Chunk: 'el -> Stream<'el>
union case Stream.Empty: Stream<'el>
union case Stream.EOF: Stream<'el>
type Iteratee<'el,'acc> =
| Continue of exn option * (Stream<'el> -> Iteratee<'el,'acc> * Stream<'el>)
| Yield of 'acc
Full name: FSharp.Monad.Iteratee.Iteratee<_,_>
union case Iteratee.Continue: exn option * (Stream<'el> -> Iteratee<'el,'acc> * Stream<'el>) -> Iteratee<'el,'acc>
type exn = System.Exception
Full name: Microsoft.FSharp.Core.exn
type 'T option = Option<'T>
Full name: Microsoft.FSharp.Core.option<_>
union case Iteratee.Yield: 'acc -> Iteratee<'el,'acc>
type Enumerator<'el,'acc> = Iteratee<'el,'acc> -> Iteratee<'el,'acc>
Full name: FSharp.Monad.Iteratee.Enumerator<_,_>
type Enumeratee<'elo,'eli,'acc> = Iteratee<'eli,'acc> -> Iteratee<'elo,Iteratee<'eli,'acc>>
Full name: FSharp.Monad.Iteratee.Enumeratee<_,_,_>
val runIteratee : m:Iteratee<'a,'b> -> 'b
Full name: FSharp.Monad.Iteratee.runIteratee
val m : Iteratee<'a,'b>
val x : 'a
union case Option.Some: Value: 'T -> Option<'T>
val e : exn
val raise : exn:System.Exception -> 'T
Full name: Microsoft.FSharp.Core.Operators.raise
val k : (Stream<'a> -> Iteratee<'a,'b> * Stream<'a>)
val fst : tuple:('T1 * 'T2) -> 'T1
Full name: Microsoft.FSharp.Core.Operators.fst
val xx : 'a
val failwith : message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.failwith
val bind : m:Iteratee<'a,'b> -> f:('b -> Iteratee<'a,'c>) -> Iteratee<'a,'c>
Full name: FSharp.Monad.Iteratee.bind
val f : ('a -> Iteratee<'b,'c>)
val e : exn option
val s : Stream<'a>
val s' : Stream<'a>
union case Option.None: Option<'T>
val i : Iteratee<'a,'b>
val m' : Iteratee<'a,'b>
Multiple items
type IterateeBuilder =
new : unit -> IterateeBuilder
member Bind : m:Iteratee<'a0,'a1> * k:('a1 -> Iteratee<'a0,'a2>) -> Iteratee<'a0,'a2>
member Combine : comp1:Iteratee<'a0,unit> * comp2:Iteratee<'a0,'a1> -> Iteratee<'a0,'a1>
member Delay : f:(unit -> Iteratee<'a0,'a1>) -> Iteratee<'a0,'a1>
member Return : x:'a0 -> Iteratee<'a1,'a0>
member ReturnFrom : m:Iteratee<'a0,'a1> -> Iteratee<'a0,'a1>
member Zero : unit -> Iteratee<'a0,unit>
Full name: FSharp.Monad.Iteratee.IterateeBuilder
--------------------
new : unit -> IterateeBuilder
val this : IterateeBuilder
member IterateeBuilder.Return : x:'a0 -> Iteratee<'a1,'a0>
Full name: FSharp.Monad.Iteratee.IterateeBuilder.Return
member IterateeBuilder.ReturnFrom : m:Iteratee<'a0,'a1> -> Iteratee<'a0,'a1>
Full name: FSharp.Monad.Iteratee.IterateeBuilder.ReturnFrom
member IterateeBuilder.Bind : m:Iteratee<'a0,'a1> * k:('a1 -> Iteratee<'a0,'a2>) -> Iteratee<'a0,'a2>
Full name: FSharp.Monad.Iteratee.IterateeBuilder.Bind
val k : ('a -> Iteratee<'b,'c>)
member IterateeBuilder.Zero : unit -> Iteratee<'a0,unit>
Full name: FSharp.Monad.Iteratee.IterateeBuilder.Zero
member IterateeBuilder.Combine : comp1:Iteratee<'a0,unit> * comp2:Iteratee<'a0,'a1> -> Iteratee<'a0,'a1>
Full name: FSharp.Monad.Iteratee.IterateeBuilder.Combine
val comp1 : Iteratee<'a,unit>
val comp2 : Iteratee<'a,'b>
member IterateeBuilder.Delay : f:(unit -> Iteratee<'a0,'a1>) -> Iteratee<'a0,'a1>
Full name: FSharp.Monad.Iteratee.IterateeBuilder.Delay
val f : (unit -> Iteratee<'a,'b>)
val iteratee : IterateeBuilder
Full name: FSharp.Monad.Iteratee.iteratee
namespace System
namespace System.Linq
namespace Microsoft.FSharp
Multiple items
module Operators
from FSharp.Monad.Iteratee
--------------------
module Operators
from Microsoft.FSharp.Core
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val split : p:('a -> bool) -> l:'a list -> 'a list * 'a list
Full name: FSharp.Monad.Iteratee.List.split
val p : ('a -> bool)
val l : 'a list
val n : int option
val tryFindIndex : predicate:('T -> bool) -> list:'T list -> int option
Full name: Microsoft.FSharp.Collections.List.tryFindIndex
val x : int
module Seq
from Microsoft.FSharp.Collections
val take : count:int -> source:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.take
val ofSeq : source:seq<'T> -> 'T list
Full name: Microsoft.FSharp.Collections.List.ofSeq
val skip : count:int -> source:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.skip
val enumerate : input:'a list -> i:Iteratee<'a,'b> -> Iteratee<'a,'b>
Full name: FSharp.Monad.Iteratee.enumerate
val input : 'a list
val xs : 'a list
val enumeratePure1Chunk : str:'a -> i:Iteratee<'a,'b> -> Iteratee<'a,'b>
Full name: FSharp.Monad.Iteratee.enumeratePure1Chunk
val str : 'a
val enumeratePureNChunk : str:seq<'a> -> n:int -> i:Iteratee<seq<'a>,'b> -> Iteratee<seq<'a>,'b>
Full name: FSharp.Monad.Iteratee.enumeratePureNChunk
val str : seq<'a>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
val n : int
val i : Iteratee<seq<'a>,'b>
val k : (Stream<seq<'a>> -> Iteratee<seq<'a>,'b> * Stream<seq<'a>>)
val s1 : seq<'a>
val s2 : seq<'a>
val counter<'a> : Iteratee<'a,int>
Full name: FSharp.Monad.Iteratee.counter
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
val step : (int -> Stream<'a> -> Iteratee<'a,int> * Stream<'a>)
val ( test counter should calculate the length of the list without modification ) : unit -> 'a
Full name: FSharp.Monad.Iteratee.( test counter should calculate the length of the list without modification )
val actual : Iteratee<int,int>
val peek : Iteratee<'a,'a option>
Full name: FSharp.Monad.Iteratee.peek
val step : (Stream<'a> -> Iteratee<'a,'a option> * Stream<'a>)
val testPeek : obj [] []
Full name: FSharp.Monad.Iteratee.testPeek
val box : value:'T -> obj
Full name: Microsoft.FSharp.Core.Operators.box
Multiple items
val char : value:'T -> char (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.char
--------------------
type char = Char
Full name: Microsoft.FSharp.Core.char
type 'T list = List<'T>
Full name: Microsoft.FSharp.Collections.list<_>
val ( test peek should return the value without removing it from the stream ) : input:char list * expected:char option -> 'a
Full name: FSharp.Monad.Iteratee.( test peek should return the value without removing it from the stream )
val input : char list
val expected : char option
val actual : Iteratee<char,char option>
val head : Iteratee<'a list,'a>
Full name: FSharp.Monad.Iteratee.head
val step : (Stream<'a list> -> Iteratee<'a list,'a> * Stream<'a list>)
val s : Stream<'a list>
Multiple items
type Exception =
new : unit -> Exception + 2 overloads
member Data : IDictionary
member GetBaseException : unit -> Exception
member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
member GetType : unit -> Type
member HelpLink : string with get, set
member InnerException : Exception
member Message : string
member Source : string with get, set
member StackTrace : string
...
Full name: System.Exception
--------------------
Exception() : unit
Exception(message: string) : unit
Exception(message: string, innerException: exn) : unit
val testHead : obj [] []
Full name: FSharp.Monad.Iteratee.testHead
val ( test head should return the value and remove it from the stream ) : input:char list * expected:char -> 'a
Full name: FSharp.Monad.Iteratee.( test head should return the value and remove it from the stream )
val expected : char
val actual : Iteratee<char list,char>
val ( test head should fail for an empty list ) : unit -> 'a
Full name: FSharp.Monad.Iteratee.( test head should fail for an empty list )
val typeof<'T> : Type
Full name: Microsoft.FSharp.Core.Operators.typeof
val drop : n:int -> Iteratee<'a,unit>
Full name: FSharp.Monad.Iteratee.drop
val step : (Stream<'a> -> Iteratee<'a,unit> * Stream<'a>)
val split : pred:(char -> bool) -> Iteratee<char list,char list>
Full name: FSharp.Monad.Iteratee.split
val pred : (char -> bool)
type bool = Boolean
Full name: Microsoft.FSharp.Core.bool
val ieContM : ((Stream<'a> -> Iteratee<'a,'b> * Stream<'a>) -> Iteratee<'a,'b> * Stream<'c>)
val step : (char list -> Stream<char list> -> Iteratee<char list,char list> * Stream<char list>)
val before : char list
val str : char list
Multiple items
module List
from FSharp.Monad.Iteratee
--------------------
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val tail : char list
val s : Stream<char list>
val ( test split should correctly split the input ) : unit -> 'a
Full name: FSharp.Monad.Iteratee.( test split should correctly split the input )
val heads : str:'a list -> Iteratee<'a list,int> (requires equality)
Full name: FSharp.Monad.Iteratee.heads
val str : 'a list (requires equality)
val loop : (int -> 'a list -> Iteratee<'a list,int>) (requires equality)
val count : int
val step : (int -> 'a list -> Stream<'a list> -> Iteratee<'a list,int> * Stream<'a list>) (requires equality)
val s : Stream<'a list> (requires equality)
val c : 'a (requires equality)
val t : 'a list (requires equality)
val c' : 'a (requires equality)
val t' : 'a list (requires equality)
val ( test heads should count the number of characters in a set of headers ) : unit -> 'a
Full name: FSharp.Monad.Iteratee.( test heads should count the number of characters in a set of headers )
val readLines : Iteratee<obj,Choice<String list,String list>>
Full name: FSharp.Monad.Iteratee.readLines
val toString : (char list -> String)
val chars : char list
Multiple items
type String =
new : value:char -> string + 7 overloads
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : value:obj -> int + 1 overload
member Contains : value:string -> bool
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EndsWith : value:string -> bool + 2 overloads
member Equals : obj:obj -> bool + 2 overloads
member GetEnumerator : unit -> CharEnumerator
member GetHashCode : unit -> int
...
Full name: System.String
--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
type Array =
member Clone : unit -> obj
member CopyTo : array:Array * index:int -> unit + 1 overload
member GetEnumerator : unit -> IEnumerator
member GetLength : dimension:int -> int
member GetLongLength : dimension:int -> int64
member GetLowerBound : dimension:int -> int
member GetUpperBound : dimension:int -> int
member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
member Initialize : unit -> unit
member IsFixedSize : bool
...
Full name: System.Array
val ofList : list:'T list -> 'T []
Full name: Microsoft.FSharp.Collections.Array.ofList
val terminators : obj
val lines : ('a -> Iteratee<obj,Choice<String list,String list>>)
val acc : 'a
val c : char
val check : (char list list -> char list -> int -> Iteratee<obj,Choice<String list,String list>>)
val acc : char list list
val l : char list
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
val rev : list:'T list -> 'T list
Full name: Microsoft.FSharp.Collections.List.rev
val map : mapping:('T -> 'U) -> list:'T list -> 'U list
Full name: Microsoft.FSharp.Collections.List.map
union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>
More information