0 people like it.

Capture the rest of sequence on error

Computation expression that automatically captures the rest of the sequence that you are iterating over using a "for" loop so that the exception handler can do something clever with it.

 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: 
// Used to wrap errors that happen inside for loop body
exception ForLoopException of exn * seq<obj>

// Basic computation builder - the only clever logic is in "for"
type AutoSeqBuilder() = 
  member x.For(s:seq<'a>, f) =
    use en = s.GetEnumerator() 
    let rec loop() = 
      if en.MoveNext() then
        // If an exception happens during the evaluation of the body,
        // capture it alognside with the unused part of the input sequence 
        try f en.Current
        with e ->
          let rest = seq {
            yield box en.Current 
            while en.MoveNext() do yield box en.Current }
          raise(ForLoopException(e, rest))
        loop ()
    loop()
  member x.Zero() = ()
  member x.Combine(a, b) = a; b()
  member x.Delay(f) = f
  member x.Run(f) = f()
  member x.Return(v) = v
  member x.TryWith(f, g) =
    try f() with e -> g e

let serr = AutoSeqBuilder()

// Example - the exception handler can access the unused part of the sequence!
serr { 
  try 
    for i in 0 .. 10 do
      if i > 5 then failwith "Too much" 
      printfn "Processing %d" i
  with ForLoopException(e, rest) ->
    for v in rest do
      printfn "Failed or skipped %O" v }
exception ForLoopException of exn * seq<obj>
type exn = System.Exception
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>
type obj = System.Object
Multiple items
type AutoSeqBuilder =
  new : unit -> AutoSeqBuilder
  member Combine : a:unit * b:(unit -> 'e) -> 'e
  member Delay : f:'d -> 'd
  member For : s:seq<'a> * f:('a -> unit) -> unit
  member Return : v:'b -> 'b
  member Run : f:(unit -> 'c) -> 'c
  member TryWith : f:(unit -> 'a) * g:(exn -> 'a) -> 'a
  member Zero : unit -> unit

--------------------
new : unit -> AutoSeqBuilder
val x : AutoSeqBuilder
val s : seq<'a>
val f : ('a -> unit)
val en : System.Collections.Generic.IEnumerator<'a>
System.Collections.Generic.IEnumerable.GetEnumerator() : System.Collections.Generic.IEnumerator<'a>
val loop : (unit -> unit)
System.Collections.IEnumerator.MoveNext() : bool
property System.Collections.Generic.IEnumerator.Current: 'a with get
val e : exn
val rest : seq<obj>
val box : value:'T -> obj
val raise : exn:System.Exception -> 'T
val a : unit
val b : (unit -> 'e)
val f : 'd
val f : (unit -> 'c)
val v : 'b
val f : (unit -> 'a)
val g : (exn -> 'a)
val serr : AutoSeqBuilder
val i : int
val failwith : message:string -> 'T
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
val v : obj
Raw view Test code New version

More information

Link:http://fssnip.net/867
Posted:4 months ago
Author:Tomas Petricek
Tags: computation expression , computation expressions , error handling