rub*_*oor 2 monads haskell either control-flow
我将举例说明我想立刻做些什么.
version1 :: IO ()
version1 =
if boolCheck
then case maybeCheck of
Nothing -> putStrLn "Error: simple maybe failed"
Just v -> case eitherCheck of
Left e -> putStrLn $ "Error: " ++ show e
Right w -> monadicBoolCheck v >>= \case
False -> putStrLn "Error: monadic bool check failed"
True -> print "successfully doing the thing"
else putStrLn "simple bool check failed"
Run Code Online (Sandbox Code Playgroud)
基本上我想在一些检查结果为正的情况下"做一件事".每当一次检查结果为否定时,我想保留有关违规检查的信息并中止任务.在现实生活中,这些检查有不同的类型,因此我打电话给他们
boolCheck :: Bool
maybeCheck :: Maybe a
eitherCheck :: Show a => Either a b
monadicBoolCheck :: Monad m => m Bool
Run Code Online (Sandbox Code Playgroud)
这只是例子.随意也可以想到monadic Maybe,EitherT或者head是一个单例列表,当它不是单例时我提取并失败.
现在我正在努力改进上面的实现,Eithermonad进入我的脑海,因为它有一个错误消息中止的概念.
version2 :: IO ()
version2 = do
result <- runEitherT $ do
if boolCheck
then pure ()
else left "simple bool check failed"
v <- case maybeCheck of
Just x -> pure x
Nothing -> left "simple maybe check failed"
w <- hoistEither . mapLeft show $ eitherCheck
monadicBoolCheck v >>= \case
True -> pure ()
False -> left "monadic bool check failed"
case result of
Left msg -> putStrLn $ "Error: " ++ msg
Right _ -> print "successfully doing the thing"
Run Code Online (Sandbox Code Playgroud)
虽然我更喜欢version2,但可读性的提高可能是微不足道的.在添加进一步检查时,Version2更胜一筹.
有这种最终的优雅方式吗?
我不喜欢的:
1)我部分地滥用了Eithermonad,我实际上做的更像是一个Maybe带有卷的monad Just并且Nothing转换为monadic bind
2)检查的转换Either需要相当冗长的使用case或转换功能(如hoistEither).
提高可读性的方法可能是:
1)定义辅助函数以允许代码
v <- myMaybePairToEither "This check failed" monadicMaybePairCheck
monadicMaybePairCheck :: Monad m => m (Maybe x, y)
...
myMaybePairToEither :: String -> m (Maybe x, y) -> EitherT m e z
myMaybePairToEither _ (Just x, y) = pure $ f x y
myMaybePairToEither msg (Nothing, _) = left msg
Run Code Online (Sandbox Code Playgroud)
2)始终使用明确的案例,甚至不使用 hoistEither
3)定义我自己的monad以阻止Either滥用...我可以提供所有转换功能(如果没有人已经做过类似的事情)
4)使用maybe和either在可能的情况
5)......?
使用maybe,either和mtl包.通过by,eitherCheck :: Show a => Either a b's Show a约束可能不是你想要的:它允许调用者选择他们想要的任何类型,只要类型实现Show a.您可能打算a成为一种类型,以便调用者只能调用show该值.大概!
{-# LANGUAGE FlexibleContexts #-}
newtype Error = Error String
gauntlet :: MonadError Error m => m ()
gauntlet = do
unless boolCheck (throw "simple bool check failed")
_ <- maybe (throw "simple maybe check failed") pure maybeCheck
_ <- either throw pure eitherCheck
x <- monadicBoolCheck
unless x (throw "monadic bool check failed")
return ()
where
throw = throwError . Error
version2 :: IO ()
version2 =
putStrLn (case gauntlet of
Left (Error e) ->
"Error: " ++ e
Right _ ->
"successfully doing thing")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
841 次 |
| 最近记录: |