Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Monad just a functional way of Error handling?

I am reading "Programming in Haskell" book and trying to correlate ideas of haskell to my knowledge in C#. Please correct me if I am wrong.

I feel like monads enforces the programmer to write code which can handle exceptions. So we will explicitly mention the error handling in the type system like

Optional(Int) functionName(Int a, Int b)

The return type is Optional(Int) but not an Int, So who so ever uses the library that has this kind of return types will understand that error handling is happening and the result will be like None(explains Something went wrong) and Some(explains we got some result).

Any code can result to Happy Path(where we get some results) and Sad Path(where errors occurs). Making this paths explicitly in Type system is what monad is. That's my understanding of it. Please correct me.

Monads are like a bridge between Pure Functional Programming and Impure code (that results in side effects).


Apart from this I want to make sure my understanding on Exception handling (VS) Option Types.

Exception Handling tries to do the operations without having a deeper look on to the inputs. Exception Handling's are Heavy since the Call stack has to unwind till it get to the Catch || Rescue || Handling Code.

And the Functional way of dealing things is check the inputs before doing the operations and return the "None" as result if the inputs does't match the required criteria. Option types are light weight of handling errors.

like image 911
Pawan Kumar Avatar asked Mar 06 '23 12:03

Pawan Kumar


2 Answers

Monad is just an interface (in Haskell terms, typeclass) that a type can implement, along with a contract specifying some restrictions on how the interface should behave.

It's not that different from how a C# type T can implement, say, the IComparable<T> interface. However, the Monad interface is quite abstract and the functions can do surprisingly different things for different types (but always respecting the same laws, and the same "flavor" of composition).

Instead of seeing Monad as a functional way of error handling, it's better to go the other way: inventing a type like Optional that represents errors / absence of values, and start devising useful functions on that type. For example, a function that produces an "inhabited" Optional from an existing value, a function that composes two Optional-returning functions to minimize repetitive code, a function that changes the value inside the Optional if it exists, and so on. All of them functions that can be useful on their own.

After we have the type and and a bevy of useful functions, we might ask ourselves:

  • Does the type itself fit the requirements for Monad? It must have a type parameter, for example.

  • Do some (not necessarily all) of the useful functions we have discovered for the type fit the Monad interface? Not only they must fit the signatures, they must fit the contract.

In the affirmative case, good news! We can define a Monad instance for the type, and now we are able to use a whole lot of monad-generic functions for free!

But even if the Monad typeclass doesn't exist in our language, we can keep in mind that the type and some of the functions defined on it behave like a Monad. From the documentation of the thenCompose method of the CompletableFuture Java class:

This method is analogous to Optional.flatMap and Stream.flatMap.

This allows us to "transfer intuitions" between seemingly unrelated classes, even if we can't write monad-generic code because the shared interface doesn't exist.

like image 173
danidiaz Avatar answered Mar 15 '23 14:03

danidiaz


Monads aren't 'just a functional way of error handling', so you are, indeed, wrong.

It would be pointless to turn this answer into a monad tutorial, so I'm not going to try. It takes some time to understand what a monad is, and the best advice I can give is to keep working with the concept until it clicks. Eventually it will.

The type described in the OP looks equivalent (isomorphic) to Haskell's more standard Maybe type, which is indeed a monad. In a pinch, it can be used for error handling, but more often you'd use another monad called Either (or types isomorphic to it), since it's better suited for that task.

A monad, though, can be many other things. Lists are monads, as are functions themselves (via the Reader monad). Trees are monads as well. These have nothing to do with error handling.

When it comes to exceptions in Haskell, I take the view that it's a legacy feature. I'd never design my Haskell code around exceptions, since exceptions aren't visible via the type system. When a function may fail to return a result, I'd let it return a Maybe, an Either, or another type isomorphic to that. This will, indeed, force the caller to handle not only the happy path, but also any failures that may occur.

like image 20
Mark Seemann Avatar answered Mar 15 '23 14:03

Mark Seemann