如何将应用验证转换为 return MonadThrow?

How to turn applicative validation to return MonadThrow?

在我看来,在 Haskell 中验证输入数据的惯用方法是通过应用链:

mkMyData :: a -> b -> c -> Maybe MyData
mkMyData x y z =
    MyData
        <$> validateA x
        <*> validateB y
        <*> validateC z

其中验证函数本身 return Maybe 值。为了使我的智能构造函数 mkMyData 更灵活,我希望它 return MonadThrow。也就是说,

mkMyData :: MonadThrow m => a -> b -> c -> m MyData

这是否需要每个验证函数 return MonadThrow 而不是 Maybe?或者是否有某种方法可以将每个验证的特定 Maybe 结果转换为更通用的 MonadThrow 而不会破坏应用结构并使代码大大复杂化?

或者换个说法?是否值得在基本库函数中争取更通用的 MonadThrow return 类型,而牺牲更复杂、不那么惯用的代码?

这个问题的答案与相同。您为新验证函数建议的类型,

mkMyData :: MonadThrow m => a -> b -> c -> m MyData

意味着它可以在任何 monad 中工作,只要该 monad 有办法扔东西。如果该函数的实现依赖于能够 return NothingJust 显式结果,那么它将不满足该条件。

相反,您必须重写当前 return Maybe a 的函数以改为依赖 MonadThrow。例如,而不是

validateA :: a -> Maybe t
validateA x | acceptable x = Just $ convert x
            | otherwise = Nothing

你需要写

validateA :: MonadThrow m => a -> m t
validateA x | acceptable x = pure $ convert x
            | otherwise = throwM $ problemWith x

(所有以x为参数的函数都已组成,需要以某种方式与您的域相关)。