What are monadic errors?

I read about monadic errors as an alternative to errors and return value exceptions. Can anyone explain and give an example of how monadic errors will work in an imperative pseudo-language (without any functional examples).

+4
source share
1 answer

Main idea:

  • the concept of success with an exit or an error with an error is encoded into a type.
  • Values ​​(or functions) of this type can be combined into another value of this type. Values ​​with different types of success can be compiled, but they must all have the same type of failure.
  • Once the error is output, the rest of the execution is short-circuited to propagate the error.

Here is a working example in C #:


// A discrimated union that can be either an error of type TError, // or a successful result of type TResult. // IsError indicates which field has a valid value. class Throws<TError, TResult> { public bool IsError; public TError Error; public TResult Result; // Make a new successful reslt of type TResult. public static Throws<TError, TResult> Success(TResult result) { Throws<TError, TResult> t = new Throws<TError, TResult>(); t.IsError = false; t.Result = result; return t; } // Make a new error of type TError. public static Throws<TError, TResult> Fail(TError error) { Throws<TError, TResult> t = new Throws<TError, TResult>(); t.IsError = true; t.Error = error; return t; } // Composition. public Throws<TError, TResultB> Bind<TResultB>( Func<TResult, Throws<TError, TResultB>> f) { if (IsError) { // If this is an error, then we can short circuit the evaluation return Throws<TError, TResultB>.Fail(Error); } // Otherwise, forward this result to the next computation. return f(Result); } } class Test { // num / demom private static Throws<string, double> Div(double num, double denom) { if (denom == 0) return Throws<string, double>.Fail("divide by zero"); return Throws<string, double>.Success(num / denom); } // Have the user enter a double. private static Throws<string, double> ReadDouble(string name) { Console.Write("{0}: ", name); string input = Console.ReadLine(); double result; if (!double.TryParse(input, out result)) return Throws<string, double>.Fail(string.Format("can't parse {0}", name)); return Throws<string, double>.Success(result); } // Read two doubles and divide them to produce the result. private static Throws<string, double> Interact() { return ReadDouble("numerator").Bind(num => ReadDouble("denominator").Bind(denom => Div(num, denom))); } public static void TestLoop() { while (true) { // Run a computation that asks the user for two numbers, // divides them and then prints out the result. Throws<string, double> t = Interact(); // Notice how the return type forces you to address the // error if you want to get to the value. if (t.IsError) { Console.WriteLine("Error: {0}", t.Error); } else { Console.WriteLine("Success: {0}", t.Result); } } } } 
0
source

All Articles