提问人:Danielo515 提问时间:10/30/2023 更新时间:11/1/2023 访问量:19
什么时候应该使用 E.altW 而不是 E.orElse?
When should I use E.altW as opposed to E.orElse?
问:
我试图理解 E.altW 和 E.orElse 之间的差异,但两者似乎都是一样的。例如,我可以构造一个 Semigroup,它使用其中任何一个连接解析函数:
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'));
正如你所看到的,结果是完全相同的。 什么时候我应该使用一个而不是另一个?或者每个的具体用例是什么?
答:
1赞
Lauren Yim
11/1/2023
#1
首先,需要注意的一点是,它与 和 和 略有不同。后缀代表“加宽”,这意味着您可以执行以下操作:altW
alt
onElseW
onElse
W
const result: Either<never, string | number> = pipe(
E.right(''),
E.altW(() => E.right(0))
)
其中生成的 Union 类型在其内部。您可以在 fp-ts 常见问题解答中阅读更多相关信息。Either
以下是 和 的类型及其对应项:alt
onElse
W
declare const alt: <E , A >(that: () => Either<E , A>) => (fa: Either<E , A>) => Either<E , A >
declare const orElse: <E1, A, E2>(onLeft: (e: E1) => Either<E2, A>) => (ma: Either<E1, A>) => Either<E2, A >
declare const altW: <E2, B >(that: () => Either<E2, B>) => <E1, A>(fa: Either<E1, A>) => Either<E2, B | A>
declare const orElseW: <E1, E2, B>(onLeft: (e: E1) => Either<E2, B>) => < A>(ma: Either<E1, A>) => Either<E2, B | A>
因为 TypeScript 类型看起来很混乱,所以这里是同样的事情,但语法类似于 Haskell:
alt :: (() -> Either e a) -> Either e a -> Either e a
orElse :: (e1 -> Either e2 a) -> Either e1 a -> Either e2 a
altW :: (() -> Either e2 b) -> Either e1 a -> Either e2 (b | a)
orElseW :: (e1 -> Either e2 b) -> Either e1 a -> Either e2 (b | a)
正如你所希望看到的,和之间的主要区别在于传递给的函数接受错误。在你传递给的函数忽略/不使用错误的情况下,并且是等效的。在这种情况下,是这里使用更合适的函数。alt
orElse
orElse
E1
onElse
alt
onElse
alt
如果要返回具有不同错误和/或成功类型的新错误,则应使用 /。Either
altW
orElseW
所以,总而言之:
- 您是否需要使用第一个错误来返回第二个错误?
- 是:使用
orElse
/orElseW
- 否:使用
alt
/altW
- 是:使用
- 第二个与第一个有不同的类型吗?
- 是:使用
orElseW
/altW
- 否:使用
orElse
/alt
- 是:使用
旁注:备选方案
您可能已经注意到,在 和 之间还有另一个区别:在 中,函数返回的 either 可以具有不同的错误类型。alt
orElse
orElse
E2
这是因为该函数来自 Alt
类型类:alt
interface Alt<F> extends Functor<F> {
readonly alt: <A>(fa: HKT<F, A>, that: LazyArg<HKT<F, A>>) => HKT<F, A>
}
在 的情况下,你可以想到 like ,所以 和 中必须相同。Either
HKT<F, A>
Either<E, A>
E
fa
that
评论