避免使用没有monad变换器的case表达式梯形图

Dan*_*rro 6 haskell coding-style monad-transformers

真实世界 中,引入Haskell monad作为一种避免代码通过使用Maybemonad 从屏幕右侧移动的方法.然而,当case语句包括其他单子像发生了什么Either或者IO,例如?

我知道使用monad变换器可以避免使用梯子,但是它们不仅仅是因为风格问题而过度杀伤吗?是否有其他惯用和轻量级的方法来处理这个?

更新:这是一个例子:

stair s = do
    s <- getLine
    case stepMaybe s of
         Nothing -> return ()
         Just s1 -> case stepEither s1 of
                         Left  _  -> return ()
                         Right s2 -> case stepList s2 of
                                          [s3:_] -> case stepMaybe s3 of
                                                         Nothing -> return ()
                                                         Just s4 -> print s4
                                          _      -> return ()
Run Code Online (Sandbox Code Playgroud)

Gab*_*lez 10

使用专为此目的而创建errors.它允许您统一各种失败的计算,以就共同的错误处理机制达成一致.

例如,假设您有两个计算,其中一个计算失败Maybe,另一个计算失败Either String:

safeHead :: [a] -> Maybe a
safeHead as = case as of
    []  -> Nothing
    a:_ -> Just a

safeDivide :: Double -> Double -> Either String Double
safeDivide x y = if y == 0 then Left "Divide by zero" else Right (x / y)
Run Code Online (Sandbox Code Playgroud)

我们可以通过两种方式使这两个函数在相同的错误处理机制上达成一致.第一种方法是通过抑制错误将Either函数转换为a .这就是函数的作用:MaybeStringhush

-- Provided by the `errors` package
hush :: Either e a -> Maybe a

example1 :: [Double] -> Maybe Double
example1 xs = do
    x <- safeHead xs
    hush (safeDivide 4 x)
Run Code Online (Sandbox Code Playgroud)

或者,如果失败,我们可以使用Maybe描述性String错误消息来注释计算.这就是note函数的作用:

-- Also provided by the `errors` package:
note :: e -> Maybe a -> Either e a

example2 :: [Double] -> Either String Double
example2 xs = do
    x <- note "Empty list" (safeHead xs)
    safeDivide 4 x
Run Code Online (Sandbox Code Playgroud)

所述errors包还包括用于转换函数MaybeTEitherT,太.这使您可以统一所有错误处理机制,以使用您选择的目标monad.

使用您的stair示例,您可以通过让他们达成一致来简化此操作MaybeT:

stair = void $ runMaybeT $ do
    s  <- lift getLine
    s4 <- hoistMaybe $ do
        s1 <-           stepMaybe  s
        s2 <- hush    $ stepEither s1
        s3 <- headMay $ stepList   s2
        stepMaybe  s3
    lift $ print s4
Run Code Online (Sandbox Code Playgroud)