8 people like it.

Iteratee

An iteratee based on https://john-millikin.com/software/enumerator/ and http://okmij.org/ftp/Haskell/Iteratee/IterateeIO-talk-notes.pdf

FSharp.Monad.Iteratee

 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()

Iteratee Samples

  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>
Next Version Raw view Test code New version

More information

Link:http://fssnip.net/6g
Posted:13 years ago
Author:Ryan Riley
Tags: iteratee , enumerator , lazy , i/o