有没有一种方法可以将IOEither和TaskEither表示为同时包含tryCatch的单个Monad
我现在将使用一个基于HTTP的应用程序接口,所以使用TaskEither是有意义的,但是我预计这段代码将会迁移到“离家更近的地方”,到那时将它变成一个IOEither也是有意义的。因此,我想以无标记的方式编写一个使用者接口
interface EngineRepository<M extends URIS2> {
calculateNumber: (i:SomeData) => Kind2<M, DomainError, number>
}
const getRepo = <M>(m:M extends URIS2):EngineRepository<M> => ({
calculateNumber: someCalculation(m)()
})
const calculateNumber = <M>(m:M extends URIS2) => flow(/* M.chain, M.map, etc. works great! */)到目前一切尚好!然而,虽然有一个选项的tryCatch,TaskEither,IOEither等,但它不是我所能说的任何接口的一部分。因此,我正在尝试创建我自己的:
interface Tryable<M extends URIS2> extends Monad2<M> {
tryCatch: <E,A>(f:Lazy<A>, onError: (reason:unknown) => E) => Kind2<M, E, A>
}
const calculateNumber = <M>(m:M extends URIS2) =>
flow(/* M.tryCatch works great now! */)这里的问题是IOError是同步的,所以f:Lazy<A>是好的,TaskEither是异步的,所以它需要改为f:Lazy<Promise<A>>。
有没有更好的方法来解决这个问题,或者这是不可能的?我是否需要一直使用TaskEither,然后添加一个步骤,将IOEither转换为TaskEither,并放弃无标记的final?
发布于 2020-12-04 02:15:15
我有一个试探性的解决方案,感觉很麻烦:
interface Tryable<M extends URIS2, ThunkType extends 'Task'|'IO'> extends MonadIO2<M> {
tryCatch: <E, A>(f:Kind<ThunkType, A>, onError: (e:unknown)=>E) => Kind2<M, E, A>
}
const te: Tryable<'TaskEither', 'Task'> = { ...TE.taskEither, tryCatch: TE.tryCatch}
const ioe: Tryable<'IOEither', 'IO'> = { ...IOE.ioEither, tryCatch: IOE.tryCatch}
pipe(te.tryCatch(()=>Promise.resolve(5),()=>'error'), te.map(num=>`${num}`)) // TaskEither<'error',string>
pipe(ioe.tryCatch(()=>5,()=>'error'), ioe.map(num => `${num}`)) // IOEither<'error',string>它可以工作,但我不喜欢它将monad和thunk类型结合在一起,原因有两个:
Option实现了Tryable,thunk类型仍然是IO。Either和其他应用程序也是如此。这就是它开始感到麻木的地方,将Option和Either与IO!紧密结合在一起
Lazy<A>和IO<A>是同一类型,而Lazy<Promise<A>>和Task<A>是同一类型。如果这种情况发生变化,此解决方案将不起作用。https://stackoverflow.com/questions/65112919
复制相似问题