Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional Programming: How to handle exceptions in Functional Programming or what is its equivalent

Let's say, I've the below code.

public int divide(int dividend, int divisor) {
    if( divisor == 0 || (dividend == Integer.MIN_VALUE && divisor == -1)) 
          throw new DivisionException();
    return dividend/divisor;
}

How to write this in Functional Programming?

I have a logic similar to the above written in Java and would like to migrate that to functional code in Haskell/Clojure. How to handle this in the callers of divide?

I know that the above code is totally imperative. It was not written with the forethought of migrating it to FP in future.

Kindly advise me with a sample code in Haskell or Clojure.

like image 273
Vicky Avatar asked Jan 05 '18 10:01

Vicky


People also ask

Is functional programming less efficient?

Efficiency issues Functional programming languages are typically less efficient in their use of CPU and memory than imperative languages such as C and Pascal. This is related to the fact that some mutable data structures like arrays have a very straightforward implementation using present hardware.

What is either in functional programming?

In most functional programming languages, there is a type called Either (or a synonym). The Either type is used to represent a value that can have two possible types. It is common to see Either used to represent a success value or a failure value, although that doesn't have to be the case.

What is functional error?

When dealing with errors in a purely functional way, we try as much as we can to avoid exceptions. Exceptions break referential transparency and lead to bugs when callers are unaware that they may happen until it's too late at runtime.


3 Answers

The divide function is not total: some values from its input domain have no image.

Make the function total

Change the output domain so that it can return either an error or a number. The caller is responsible for checking whether the value is really a number, or an error.

In a dynamically typed language like Clojure, you could return nil, but any other value could work too, as long as you can distinguish it from a number. In a statically typed language like Haskell, use Data.Either or your own datatype if you need.

  • The check is done consistently and statically in Haskell. You must do the check every time, even if you are sure the divisor can't be null. However, you can also have a wrapper function, must-divide, which then would throws an exception on errors.

  • In Clojure, you may forget to check for nil, either from a bug or because you have more information about the divisor than the compiler. You could however force a consistent checking by exporting a divide macro that requires you to consider the error path:

    (divide x y :on-error (throw ...))
    (divide x y :on-error default-value)
    

    ... could be respectively expanded as:

    (or (maybe-divide x y) (throw ...))
    (or (maybe-divide x y) default-value)
    

    ... with

    (defn maybe-divide [dividend divisor]
      (and (not (zero? divisor)) 
           (or (not= Integer/MIN_VALUE dividend)
               (not= -1 divisor))
           (/ dividend divisor)))
    

Throw an exception

Mathematical operations are composed to form bigger expressions: adding an explicit error handling path inside them can quickly become unreadable. Also, you may expect most of your operations to call divide with valid inputs, and don't want to check if the result is valid each time you call it (e.g. some mathematical equation come with a proof that the divisor won't possibly ever be null). In that case, Clojure and Haskell support exceptions. This allows you to catch errors higher up in the call stack in case you have bugs.

like image 197
coredump Avatar answered Sep 23 '22 11:09

coredump


The following shows how you could do it in Haskell.

Based on the type siginure divide :: Int -> Int -> Either [Char] Int you can see that the function divide will return either a Left string or a Right Int.

Either is an algebraic data structure and there are many more and you can write your own to.

divide :: Int -> Int -> Either [Char] Int
divide dividend divisor
    | (divisor == 0) = Left "Sorry, 0 is not allowed :o"
    | (dividend == (minBound :: Int)) && (divisor == -1) = Left "somethig went wrong"
    | otherwise = Right (dividend `div` divisor)

main = do
    print (divide 4 2)                     -- Right 2
    print (divide 4 0)                     -- Left "Sorry, 0 is not allowed :o"
    print (divide (minBound :: Int) (-1))  -- Left "somethig went wrong"

You can play with it on repl.it

In Haskell you can throw errors to with error "and your error message" but this will crash you programm.. and this is not what we want.

like image 22
Roman Avatar answered Sep 24 '22 11:09

Roman


In Clojure this isn't really different from Java:

(defn divide
  [dividend divisor]
  (if (or (zero? divisor)
          (and (= Integer/MIN_VALUE
                  dividend)
               (= -1 divisor)))
    (throw (DivisionException.))
    (/ dividend divisor)))

Your code isn't mutating any variables and therefore is already pretty much functional. Exceptions are just as much a part of Clojure, because it adopts the execution model of the JVM.

like image 40
Michiel Borkent Avatar answered Sep 26 '22 11:09

Michiel Borkent