Search code examples
f#pointfree

Exception handling in point-free functions


I'm stuck with a seemingly trivial problem: I'm unable to handle an exception in a function if it's written in a point-free manner.

Consider these two functions:

let divide1 x y =
    try
        x / y
    with
        | :? System.DivideByZeroException -> 42

let divide2 =
    try
        (/)
    with
        | :? System.DivideByZeroException -> fun _ _ -> 42

let x1 = divide1 5 0 // works fine
let x2 = divide2 5 0 // doesn't handle an exception

Although both functions are seemingly same, they have different types:

val divide1: int -> int -> int
val divide2: (int -> int -> int)

Obviously, divide2 does not even attempt to handle an exception. It simply returns an operator.

What can I do in order to make divide2 handle the exception in a proper manner (except specifically declaring its arguments)?


Solution

  • This is one of the reasons why I find the point-free style problematic. It makes it difficult to use standard language constructs like try .. with (or standard loops and other F# features) and you need to replace them with custom combinators. In this case, you could define combinator tryWith2 that wraps a two-argument function in an exception handler:

    let tryWith2 f h a b = 
      try f a b // Call the function with two arguments
      with e -> 
        // Try running the error handler with the exception
        match h e with 
        | Some g -> g a b // Error handler provided another function
        | _ -> reraise()  // Error was not handled - reraise
    

    Then you could write the function in a point-free style like this (the error handling is still not-point-free, but I do not want to make this too silly :-))

    let divide2 =
      tryWith2 (/) (function
          | :? System.DivideByZeroException -> Some(fun _ _ -> 42)
          | _ -> None)
    
    let x1 = divide2 5 0 // returns 42
    let x2 = divide2 5 1 // returns 5
    

    Of course, the point free style is useful, even in F#. For example, when writing a DSL, it is a great way to compose declarative specification (because the primitives express something using higher-level of abstraction). Here, you need to express something that is quite close to normal F# code and, I believe, that is best expressed as normal F# code.