我经常遇到这种情况,我需要完成几个连续的操作。如果每个操作都专门使用上一步中的数据,那么我可以很乐意做类似的事情pipe(startingData, TE.chain(op1), TE.chain(op2), TE.chain(op3), ...)。op2当还需要来自 的数据时,我找不到一个好的方法来编写此代码startingData,而无需一堆嵌套回调。
如何避免下面示例中的厄运金字塔?
declare const op1: (x: {one: string}) => TE.TaskEither<Error, string>;
declare const op2: (x: {one: string, two: string}) => TE.TaskEither<Error, string>;
declare const op3: (x: {one: string, two: string, three: string}) => TE.TaskEither<Error, string>;
pipe(
TE.of<Error, string>('one'),
TE.chain((one) =>
pipe(
op1({ one }),
TE.chain((two) =>
pipe(
op2({ one, two }),
TE.chain((three) => op3({ one, two, three }))
)
)
)
)
);
Run Code Online (Sandbox Code Playgroud)
这个问题有一个解决方案,它被称为“do notation”。它已经推出了fp-ts-contrib一段时间,但现在它还有一个fp-ts使用该bind函数(在所有单子类型上定义)的内置版本。基本思想与我下面所做的类似 - 我们将计算结果绑定到特定名称,并在进行过程中跟踪“上下文”对象内的这些名称。这是代码:
pipe(
TE.of<Error, string>('one'),
TE.bindTo('one'), // start with a simple struct {one: 'one'}
TE.bind('two', op1), // the payload now contains `one`
TE.bind('three', op2), // the payload now contains `one` and `two`
TE.bind('four', op3), // the payload now contains `one` and `two` and `three`
TE.map(x => x.four) // we can discharge the payload at any time
)
Run Code Online (Sandbox Code Playgroud)
我提出了一个我不太自豪的解决方案,但我分享它以获取可能的反馈!
首先,定义一些辅助函数:
function mapS<I, O>(f: (i: I) => O) {
return <R extends { [k: string]: I }>(vals: R) =>
Object.fromEntries(Object.entries(vals).map(([k, v]) => [k, f(v)])) as {
[k in keyof R]: O;
};
}
const TEofStruct = <R extends { [k: string]: any }>(x: R) =>
mapS(TE.of)(x) as { [K in keyof R]: TE.TaskEither<unknown, R[K]> };
Run Code Online (Sandbox Code Playgroud)
mapS允许我将函数应用于对象中的所有值(子问题 1:是否有内置函数允许我执行此操作?)。使用此函数将值的结构转换为这些值TEofStruct的 s 结构。TaskEither
TEofStruct我的基本想法是使用和累积新值以及以前的值sequenceS。到目前为止,它看起来像这样:
pipe(
TE.of({
one: 'one',
}),
TE.chain((x) =>
sequenceTE({
two: op1(x),
...TEofStruct(x),
})
),
TE.chain((x) =>
sequenceTE({
three: op2(x),
...TEofStruct(x),
})
),
TE.chain((x) =>
sequenceTE({
four: op3(x),
...TEofStruct(x),
})
)
);
Run Code Online (Sandbox Code Playgroud)
感觉我可以编写某种辅助函数,结合使用来sequenceTE减少TEofStruct这里的样板文件,但我仍然不确定总体上这是否是正确的方法,或者是否有更惯用的模式!
| 归档时间: |
|
| 查看次数: |
2220 次 |
| 最近记录: |