在我看来,在Haskell中验证输入数据的惯用方式是通过应用链:
mkMyData :: a -> b -> c -> Maybe MyData
mkMyData x y z =
MyData
<$> validateA x
<*> validateB y
<*> validateC z
其中验证函数本身返回Maybe
值。为了使我的智能构造函数mkMyData
更灵活,我希望它返回MonadThrow
。也就是说,
mkMyData :: MonadThrow m => a -> b -> c -> m MyData
这是否需要每个验证函数返回MonadThrow
而不是Maybe
?还是有某种方法可以将每个验证的特定Maybe
结果转换为更通用的MonadThrow
,而不会破坏应用结构并大大简化代码?
或者也许换个说法?是否有必要在基本库函数中争取更通用的MonadThrow
返回类型,而以更复杂,更惯用的代码为代价?
mkMyData :: MonadThrow m => a -> b -> c -> m MyData
表示它完全可以在任何monad中工作,只要该monad有扔东西的方式。如果该函数的实现依赖于能够显式返回Nothing
或Just
结果,则它将不满足该条件。相反,您必须重写当前返回
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
作为参数的函数都已组成,需要以某种方式与您的域相关联。