Hone logo
Hone
Problems

Implementing the Either Monad in TypeScript

The Either monad is a powerful tool in functional programming for representing computations that can result in one of two possible outcomes: a success or a failure. Implementing an Either type in TypeScript allows you to handle potential errors gracefully and chain operations in a more readable and maintainable way, avoiding deeply nested if/else statements or try/catch blocks. This challenge asks you to create a robust Either type with associated utility functions.

Problem Description

You are tasked with implementing an Either type in TypeScript. This type should represent a value that can be either a Left (representing a failure or error) or a Right (representing a success). Your implementation should include the following:

  • Either<L, R> Type: A generic type parameterized by two types, L (Left, representing the error type) and R (Right, representing the success type).
  • Left<L> Constructor: A constructor to create an Either instance representing a failure, holding a value of type L.
  • Right<R> Constructor: A constructor to create an Either instance representing a success, holding a value of type R.
  • isLeft() Method: A method that returns true if the Either instance represents a failure (Left), and false otherwise.
  • isRight() Method: A method that returns true if the Either instance represents a success (Right), and false otherwise.
  • getLeft() Method: A method that returns the value held in a Left instance. This method should throw an error if called on a Right instance.
  • getRight() Method: A method that returns the value held in a Right instance. This method should throw an error if called on a Left instance.
  • map<U>(f: (r: R) => U): Either<L, U> Method: A method that applies a function f to the value inside a Right instance and returns a new Either instance with the result. If the Either instance is a Left, it should return the original Left instance unchanged.
  • flatMap<U>(f: (r: R) => Either<L, U>): Either<L, U> Method: A method that applies a function f to the value inside a Right instance. The function f should return another Either instance. This method chains these Either instances together, effectively flattening them. If the original Either instance is a Left, it should return the original Left instance unchanged.

Examples

Example 1:

Input: new Right<number, string>("Success!")
Output: { isLeft: false, isRight: true, getRight: () => "Success!", getLeft: () => { throw new Error("Called getLeft on Right") } }
Explanation: Creates a Right Either with the value "Success!".

Example 2:

Input: new Left<string, number>("An error occurred!")
Output: { isLeft: true, isRight: false, getLeft: () => "An error occurred!", getRight: () => { throw new Error("Called getRight on Left") } }
Explanation: Creates a Left Either with the value "An error occurred!".

Example 3:

const either1 = new Right<string, number>(10);
const either2 = either1.map(x => x * 2);
console.log(either2.getRight()); // Output: 20

const either3 = new Left<string, number>("Error!");
const either4 = either3.map(x => x * 2);
console.log(either4.getLeft()); // Output: "Error!"

const either5 = new Right<string, Either<string, number>>(new Left<string, number>("Error"));
const either6 = either5.flatMap(x => x);
console.log(either6.getLeft()); // Output: "Error"

Explanation: Demonstrates map and flatMap functionality, including handling of Left cases.

Constraints

  • The getLeft() and getRight() methods must throw an error if called on the incorrect type of Either instance.
  • The map and flatMap methods should be immutable; they should return new Either instances instead of modifying the original.
  • The code should be well-typed and adhere to TypeScript best practices.
  • No external libraries are allowed.

Notes

  • Consider using discriminated unions to distinguish between Left and Right instances.
  • Think about how to handle the error cases gracefully and consistently.
  • The flatMap method is crucial for chaining operations that themselves return Either instances. It's a key part of the monad's power.
  • Focus on creating a type-safe and robust implementation.
Loading editor...
typescript