结合两个任一个Monad的结果
你如何在 Haskell 中处理这种情况(下面提供的伪代码)?
x = somethingThatReturnsMaybe(s1)
y = somethingThatReturnsMaybe(s2)
if(x == Nothing) return Left "invalid x"
if(y == Nothing) return Left "invalid y"
callFn(fromJust(x), fromJust(y));
我可以想到两种方法:-
- 从调用处传递Maybes,这样上面的代码就可以包装在一个函数中,我可以在函数绑定/定义中使用模式匹配。
- 我已经编写了这段代码来使用任一组合这些值
mapToRight ((x, y) -> callFn x y) combined_values
where { combined_values = (maybeToRight "Invalid x!" x >>= combiner) <*>
maybeToRight "Invalid target position" y;
mapToRight = second; x = somethingThatReturnsMaybe s1; y = somethingThatReturnsMaybe s2
}
对于第二个选项,我有以下组合器
combiner :: b -> Either a (b0 -> (b, b0));
combiner x = Right (x,)
maybeToRight :: a -> Maybe b -> Either a b
maybeToRight a Nothing = Left a
maybeToRight a (Just x) = Right x
这两者之间是否有任何偏好(虽然第一个对我来说不太可取,因为它可能涉及更多的变化),或者有没有更好的选择?
回答
我会导入Control.Error,然后写这个:
do
x <- note "invalid x" (somethingThatReturnsMaybe s1)
y <- note "invalid y" (somethingThatReturnsMaybe s2)
callFn x y
这note是您的maybeToRight. 的Either的的实现(>>=)是处理解缠/组合。
- +1, I didn't know about `note`. Given that it's literally `note a = maybe (Left a) Right`, one might question if it's so close to the [Fairbairn threshold](https://wiki.haskell.org/Fairbairn_threshold) that it'd be easier just to use `maybe` instead of importing `Control.Error`...