3 people like it.

Attempt to implement a tail calling exception handling combinator

See also https://fslang.uservoice.com/forums/245727-f-language/suggestions/6536829-implement-ocaml-s-new-match-exception-syntax

The combinator

1: 
2: 
3: 
4: 
5: 
6: 
7: 
let inline matchExn (f : 'T -> 'S) (t : 'T) (onSuccess : 'S -> 'R) (onException : exn -> 'R) : 'R =
    let mutable exn : System.Exception = null
    let mutable s = Unchecked.defaultof<'S>
    try s <- f t with e -> exn <- e // e cannot be null
    if obj.ReferenceEquals(exn, null) then onSuccess s
    else
        onException exn

Simple example

 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: 
let test () =
    matchExn (fun i -> 1 / i) 0
        (fun r -> string r)
        (fun e -> e.Message)

// Codegen (Release build)
//
//public static string test2()
//{
//	Exception ex = null;
//	int r = 0;
//	try
//	{
//		r = 1 / 0;
//	}
//	catch (object arg_0D_0)
//	{
//		Exception ex2 = (Exception)arg_0D_0;
//		ex = ex2;
//	}
//	if (object.ReferenceEquals(ex, null))
//	{
//		return Exn.onSuccess@38-1(r);
//	}
//	return ex.Message;
//}

Tail recursive, exception safe iteration

 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: 
let countIters (f : int -> bool) =
    let rec aux i =
        matchExn f i
            (function true -> aux (i+1) | false -> i)
            (fun _ -> i)

    aux 0

// does not stack overflow, unless running on mono
countIters (fun i -> let _ = 1 / (100000 - i) in true) 

// Codegen (Release build)
//
//public static int countIters(FSharpFunc<int, bool> f)
//{
//	return Exn.aux@54(f, 0);
//}
//internal static int aux@54(FSharpFunc<int, bool> f, int i)
//{
//	Exception objA = null;
//	bool b = false;
//	try
//	{
//		b = f.Invoke(i);
//	}
//	catch (object arg_11_0)
//	{
//		Exception ex = (Exception)arg_11_0;
//		objA = ex;
//	}
//	if (object.ReferenceEquals(objA, null))
//	{
//		return Exn.onSuccess@38-2(f, i, b);
//	}
//	return i;
//}
val matchExn : f:('T -> 'S) -> t:'T -> onSuccess:('S -> 'R) -> onException:(exn -> 'R) -> 'R

Full name: Script.matchExn
val f : ('T -> 'S)
val t : 'T
val onSuccess : ('S -> 'R)
val onException : (exn -> 'R)
type exn = System.Exception

Full name: Microsoft.FSharp.Core.exn
Multiple items
val mutable exn : System.Exception

--------------------
type exn = System.Exception

Full name: Microsoft.FSharp.Core.exn
namespace System
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

--------------------
System.Exception() : unit
System.Exception(message: string) : unit
System.Exception(message: string, innerException: exn) : unit
val mutable s : 'S
module Unchecked

from Microsoft.FSharp.Core.Operators
val defaultof<'T> : 'T

Full name: Microsoft.FSharp.Core.Operators.Unchecked.defaultof
val e : exn
type obj = System.Object

Full name: Microsoft.FSharp.Core.obj
System.Object.ReferenceEquals(objA: obj, objB: obj) : bool
val test : unit -> string

Full name: Script.test
val i : int
val r : int
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
property System.Exception.Message: string
val countIters : f:(int -> bool) -> int

Full name: Script.countIters
val f : (int -> bool)
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<_>
type bool = System.Boolean

Full name: Microsoft.FSharp.Core.bool
val aux : (int -> int)

More information

Link:http://fssnip.net/pF
Posted:2 years ago
Author:Eirik Tsarpalis
Tags: exceptions , ocaml