2 people like it.

A failed attempt at evaluating sequence items in terms of a try-with block

A broken code example demonstrating how it's you can't catch a single throwing enumeration and continue with F#'s IEnumerable.

 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: 
// Note that this is incorrect. 

open System
open System.Linq

module Seq =
    let catchExceptions handler (sequence: _ seq) =
        let e = sequence.GetEnumerator()
        let evaluateNext () = 
            try Some (e.Current)
            with ex -> handler ex 
        seq { while e.MoveNext() do
                  match evaluateNext() with
                  | Some (item) -> yield item 
                  | None -> () }

// Won't work because e.MoveNext() is actually where the exception would be thrown.
// So I tried:

let catchExceptions handler (sequence: _ seq) =
    let e = sequence.GetEnumerator()
    let safeMoveNext() = 
        try
            e.MoveNext() 
        with ex -> 
            handler ex
            true
    seq { 
        while safeMoveNext() do
            yield e.Current
    }

// This is closer, but also doesn't work.  
// It turns out that if F#'s seq e.MoveNext() implementation throws an exception 
// it does not advance to the next element.  This makes it effectively call 
// the handler over and over ad infinitum. 

// I haven't been able to find anything about what IEnumerator should do in 
// this case, so it's not really a bug. A bit disappointing that you have to make
// sure all exceptions are handled up front when you parallelize though.

// Ah well, better luck next time :)

 
namespace System
namespace System.Linq
module Seq

from Microsoft.FSharp.Collections
val catchExceptions : handler:(exn -> 'a option) -> sequence:seq<'a> -> seq<'a>

Full name: Script.Seq.catchExceptions
val handler : (exn -> 'a option)
val sequence : 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 e : Collections.Generic.IEnumerator<'a>
Collections.Generic.IEnumerable.GetEnumerator() : Collections.Generic.IEnumerator<'a>
val evaluateNext : (unit -> 'a option)
union case Option.Some: Value: 'T -> Option<'T>
property Collections.Generic.IEnumerator.Current: 'a
val ex : exn
Collections.IEnumerator.MoveNext() : bool
val item : 'a
union case Option.None: Option<'T>
val catchExceptions : handler:(exn -> unit) -> sequence:seq<'a> -> seq<'a>

Full name: Script.catchExceptions
val handler : (exn -> unit)
val safeMoveNext : (unit -> bool)

More information

Link:http://fssnip.net/4p
Posted:6 years ago
Author:Rick Minerich
Tags: seq , sequences , collections , error handling