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