Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception handling in point-free functions

Tags:

f#

pointfree

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

like image 844
bytebuster Avatar asked Oct 24 '25 20:10

bytebuster


1 Answers

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.

like image 86
Tomas Petricek Avatar answered Oct 27 '25 14:10

Tomas Petricek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!