Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F#: Some, None, or Exception?

I have been teaching myself F# lately, and I come from an imperative (C++/C#) background. As an exercise I have been working on functions that can do stuff with matrices, like add, multiply, get determinants, etc. Everything is going well in this regard, but I find that maybe I am not making the best decisions when it concerns handling invalid inputs, for example:

// I want to multiply two matrices
let mult m1 m2 =
  let sizeOK = validateDims m1 m2

  // Here is where I am running to conceptual trouble:
  // In a C# world, I would throw an exception.
  if !sizeOK then
    raise (InvalidOperationException("bad dimensions!")
  else
    doWork m1 m2  

So while this technically works, is this appropriate for a functional language? Is it in the spirit of functional programming? Or would it make more sense to rewrite it as:

let mult m1 m2 =
  let sizeOK = validateDims m1 m2

  if !sizeOK then
    None
  else
    Some doWork m1 m2  

In this case I am returning an option, which adds an extra layer around the matrix, but I could also use the results of the function, even in failure cases (None) with pattern matching, etc. at some later point in the program. So is there a best practice for these types of scenarios? What would a functional programmer do?

like image 314
A.R. Avatar asked Aug 27 '13 15:08

A.R.


People also ask

How can I log into Facebook for free?

Go to m.facebook.com on your mobile browser. Enter one of the following: Email: You can log in with any email that's listed on your Facebook account. Phone number: If you have a mobile number confirmed on your account, you can enter it here (don't add any zeros before the country code, or any symbols).

What is Mtouch Facebook?

Facebook Touch is an advanced Facebook app that has many distinct features. H5 apps developed it as an app made especially for touchscreen phones. Available and applicable across all smartphones, Facebook Touch offers a fine user interface and serves as an alternative to the typical Facebook App.


1 Answers

I tend to avoid exceptions for the following reasons:

  • .NET exceptions are slow
  • Exceptions change control flows of programs in an unexpected way, which makes it much harder to reason about
  • Exceptions often arise in critical situations while you can fail-safe by using options.

In your case, I will follow F# core library conventions (e.g. List.tryFind and List.find, etc.) and create both versions:

let tryMult m1 m2 =
  let sizeOK = validateDims m1 m2

  if not sizeOK then
    None
  else
    Some <| doWork m1 m2

let mult m1 m2 =
  let sizeOK = validateDims m1 m2

  if not sizeOK then
    raise <| InvalidOperationException("bad dimensions!")
  else
    doWork m1 m2 

This example isn't exceptional enough to use exceptions. The mult function is included for C# compatibility. Someone using your library in C# doesn't have pattern matching to decompose options easily.

One drawback with options is that they don't give the reason why the function didn't produce a value. It's overkill here; generally Choice (or Either monad in Haskell term) is more suitable for error handling:

let tryMult m1 m2 =
  // Assume that you need to validate input
  if not (validateInput m1) || not (validateInput m2) then
     Choice2Of2 <| ArgumentException("bad argument!")
  elif not <| validateDims m1 m2 then
    Choice2Of2 <| InvalidOperationException("bad dimensions!")
  else
    Choice1Of2 <| doWork m1 m2

It's a pity that F# Core lacks high-order functions to manipulate Choice. You can find those functions in FSharpX or ExtCore library.

like image 156
pad Avatar answered Oct 02 '22 12:10

pad