…from Data.Either

Data.Either provided a disjunction to model the result of functions that could fail. Folktale 2 has changed a few things around and this data structure is now called Result, with Ok and Error as its variant tags. This page explains how to migrate from the old Data.Either to the new Result object. You can look at the full documentation for Result for more detailed information.

Contents

Constructing

Constructing values of Either was done previously as:

const Either = require('data.either');

Either.Left(1);
Either.Right(2);

With Result, this is now done as follows:

const Result = require('folktale/result');

Result.Error(1);
Result.Ok(2);

So, the type name is now Result. The Left constructor is now Error, to better indicate that it’s used for representing failures. The Right constructor is now Ok, to better indicate that it’s used for representing successes.

Pattern matching

Previously, it was possible to pattern match on an Either value by using .cata(patterns). This method would take the value inside of the data structure and pass it as a positional argument to the proper function:

const Either = require('data.either');

Either.Left(1).cata({
  Left:  (value) => value + 1,
  Right: (value) => value - 1
});
// ==> 2

Now, the preferred method in Result is .matchWith(patterns), which works similarly, but passes an object with the fields instead of each value as a positional argument:

const Result = require('folktale/result');

Result.Error(1).matchWith({
  Error: (x) => x.value + 1,
  Ok:    (x) => x.value - 1
});
// ==> 2

Testing instances

Previously, Either had isLeft and isRight boolean properties, which could be accessed to test whether a particular value was a Left or a Right:

const Either = require('data.either');

const x = Either.Left(1);
const y = Either.Right(2);

x.isLeft;  // ==> true
x.isRight; // ==> false

y.isLeft;  // ==> false
y.isRight; // ==> true

Folktale 2 replaces these with a .hasInstance(value) function on the variant constructors and on the type. Variant testing can now be safely done with this function, including on values that may be null or undefined:

const Result = require('folktale/result');

const x = Result.Error(1);
const y = Result.Ok(2);

Result.Error.hasInstance(x); // ==> true
Result.Error.hasInstance(y); // ==> false

Result.Ok.hasInstance(x); // ==> false
Result.Ok.hasInstance(y); // ==> true

You can also test if a value is of a particular type by using the type’s .hasInstance function:

Result.hasInstance(x);    // ==> true
Result.hasInstance(y);    // ==> true
Result.hasInstance(null); // ==> false

Either.try

Previously, Either.try(f) could be used to transform a function that throws errors into a function that returns an Either type:

function divide(x, y) {
  if (y === 0) {
    throw new Error('division by zero');
  } else {
    return x / y;
  }
}
const Either = require('data.either');

const safeDivide = Either.try(divide);
safeDivide(4, 2); // ==> Either.Right(2)
safeDivide(4, 0); // ==> Either.Left([Error: division by zero])

The new try function takes a thunk instead, and executes it right away:

const Result = require('folktale/result');

Result.try(_ => divide(4, 2)); // ==> Result.Ok(2)
Result.try(_ => divide(4, 0)); // ==> Result.Error([Error: division by zero])

You’d have to construct a safe version of a function explicitly:

const safeDivide = (x, y) => Result.try(divide(x, y));

safeDivide(4, 2); // ==> Result.Ok(2)
safeDivide(4, 0); // ==> Result.Error([Error: division by zero])

Either.ap

The new applicativeFn.apply(applicativeValue) method is the recommended way of using applicative functors now, which is standardised across Folktale and independent of Fantasy-Land changes.

.apply and .ap still have the same semantics, but those semantics are different from the new fantasy-land/ap function! In order to write functions that are generic over different Fantasy-Land implementations and versions, the new fantasy-land module should be used instead.

Equality testing

Previously Either had a .isEqual method, which checked if two either values had the same tag and the same value (compared by reference):

const Either = require('data.either');

Either.Left(1).isEqual(Either.Left(1));
// ==> true

Either.Right([1]).isEqual(Either.Right([1]));
// ==> false

Now, Result and other Folktale structures have a .equals method that does a similar test, but compares values structurally if they’re Fantasy-Land setoids, arrays, or plain JavaScript objects:

const Result = require('folktale/result');

Result.Error(1).equals(Result.Error(1));
// ==> true

Result.Ok([1]).equals(Result.Ok([1]));
// ==> true

More details can be found on the Equality derivation documentation.

Either.get

Previously, Either had a .get() method that would extract the value out of a Right structure, but throw an error if you had a Left structure:

const Either = require('data.either');

Either.Left(1).get();  // ==> [Error: Can't extract the value of a Left(a)]
Either.Right(1).get(); // ==> 1

This was unsafe, so in order to clearly signal that Folktale 2 has deprecated all .get() methods, and introduced a new .unsafeGet() one. You may use the new .unsafeGet() one if you really know what you’re doing, but the method name now signals that you should be careful with it:

const Result = require('folktale/result');

Result.Ok(1).unsafeGet();    // ==> 1
Result.Error(1).unsafeGet(); // ==> [Error: Can't extract the value of an Error]

You’re strongly encouraged to use the .getOrElse(default) method instead, which does not suffer from the same partiality problem:

Result.Ok(1).getOrElse(null);    // ==> 1
Result.Error(1).getOrElse(null); // ==> null

Either.leftMap

Previously, Either had a .leftMap(f) method, which worked like .map(f) for Left values:

const Either = require('data.either');

Either.Left(1).leftMap(x => x + 1);
// ==> Either.Left(2)

This was a mess, with each structure naming that method in a different way. Folktale 2 standardises these as map{Tag} instead. So Result gets a .mapError(f):

const Result = require('folktale/result');

Result.Error(1).mapError(x => x + 1);
// ==> Result.Error(2)