I'm trying to understand the diference between E.altW and E.orElse, but both seem to do the same. For example, I can construct a Semigroup that concatenates parsing functions using either of them:
import * as E from 'fp-ts/Either';
import * as A from 'fp-ts/Array';
import { pipe } from 'fp-ts/function';
import * as S from 'fp-ts/Semigroup';
const parseString = (u: unknown): E.Either<string, string> =>
typeof u === 'string' ? E.right(u) : E.left('not a string');
const parseNumber = (u: unknown): E.Either<string, number> =>
typeof u === 'number' ? E.right(u) : E.left('not a number');
const ParseSemigroup: S.Semigroup<
(u: unknown) => E.Either<string, string | number>
> = {
concat(a, b) {
return (input) =>
pipe(
a(input),
E.altW(() => b(input))
);
},
};
const ParseSemigroup2: S.Semigroup<
(u: unknown) => E.Either<string, number | string>
> = {
concat(a, b) {
return (input) =>
pipe(
a(input),
E.orElse(() => b(input))
);
},
};
const manyParsers = S.concatAll(ParseSemigroup)(parseNumber)([parseString]);
console.log(manyParsers('99'));
const manyParsers2 = S.concatAll(ParseSemigroup2)(parseNumber)([parseString]);
console.log(manyParsers('99'));
And the result is exactly the same, as you can see. When should I use one over the other? or what are the specific usecases of each?
First, one thing to note is that
altW
is slightly different fromalt
and likewise foronElseW
andonElse
. TheW
suffix stands for ‘widen’ and it means you can do things like this:where the resulting
Either
has a union type inside of it. You can read more about this on the fp-ts FAQ.Here’s the types of
alt
andonElse
and theirW
counterparts:Because TypeScript types can look pretty messy, here’s the same thing but with a Haskell-like syntax:
As you can hopefully see, the main difference between
alt
andorElse
is that the function passed intoorElse
takes in the errorE1
. In your case where the function passed toonElse
ignores/does not use the error,alt
andonElse
are equivalent. In this case,alt
is the more appropriate function to use here.If you want to return a new
Either
with a different error and/or success type, then you should usealtW
/orElseW
.So, in summary:
orElse
/orElseW
alt
/altW
orElseW
/altW
orElse
/alt
Side note: Alternative
You may have noticed that there’s another difference between
alt
andorElse
: inorElse
, the either returned by the function can have a different error typeE2
.This is because the
alt
function comes from theAlt
typeclass:In the case of
Either
, you can think ofHKT<F, A>
likeEither<E, A>
, so theE
has to be the same both infa
andthat
.