考虑以下组合
for {
v1 <- transform1(v)
v2 <- transform2(v1)
v3 <- transformThatErrors(v2)
v4 <- transfrom4(v3)
} yield { v4 }
是否有一个 monad M
允许上面的计算结果为 M(v2)
?
我正在尝试模拟一种情况,其中程序应应用完整的转换链直到第一个转换失败,在这种情况下,链将评估最后一个成功的转换。在最坏的情况下,整个链代表identity(v)
。
诸如 Either
和 Option
这样的 Monad 不符合此要求,因为在出现错误时,它们会将整个链评估为错误,而链则需要始终评估走向成功。换句话说,我希望程序尽可能多地做它能做的事情,但如果它什么也做不了,那也没关系。
最佳答案
Either
单子(monad)做正是您想要的。 Either
接口(interface)中没有任何内容强制您对 Left
和 Right
大小写使用不同的类型。特别是,Left
类型参数可以与Right
类型参数相同,它们都可以等于Result
(或“PartialSuccess
"?),您可以在其中定义 Result
的构成。
因此,您只需将所有 transformN
函数声明为具有返回类型
def transformN(previousStep: Result): Either[Result, Result] = ???
最后,您将其折叠
为一个结果:
val res: Result = (for {
v1 <- transform1(v)
v2 <- transform2(v1)
v3 <- transformThatErrors(v2)
v4 <- transfrom4(v3)
} yield v4).fold(
partialRes => partialRes,
completeRes => completeRes
)
甚至只是
.fold(identity, identity)
一旦第一个转换失败,Either
就会将部分结果打包为 Left
并返回它,而不应用任何进一步的转换。如果每个转换步骤都成功,则最终结果将作为 Right
返回。无论转换在哪一点停止,最终的折叠
都会从中提取(部分)结果。
如果我理解正确,您可能想到的所有其他单子(monad) M
本质上与 Either[Result, Result]
相同,但有一些特殊的 getResult
方法,相当于.fold(identity, Identity)
,因此不需要增加不必要的实体。
关于scala - 如何评估对链中最后成功步骤的理解?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50204765/