如何将此函数从 ExceptT 转换为 Haskell 中的 Except?

How can I convert this function from ExceptT to Except in Haskell?

我对 Except 感到很困惑,特别是因为网络上没有好的教程。我不知道如何将此函数从 ExceptT 转换为 Except:

data Error = Empty deriving (Show)

badFunction :: ExceptT Error IO ()
badFunction = throwError Empty

main :: IO ()
main = do
    caught_result <- runExceptT badFunction
    case caught_result of
      Left _ -> putStrLn "caught some error"
      Right _ -> putStrLn "no errors were caught"

badFunction 应该是 ExceptT Error IO () 的原因是因为 runExceptT 的类型是 runExceptT :: ExceptT e m a -> m (Either e a)。由于您的 main 类型为 main :: IO (),这意味着 runExceptT badFunction 需要是 IO …,因此 ExceptT e m a 中的 m 应该是 IO

但是你本身并不需要这个,你的 badFunction 不做任何 IO,所以你可以将它定义为 Except:

badFunction :: <b>Except</b> Error ()
badFunction = throwE Empty

然后你可以在一个IO ()中使用它,通过使用runIdentity来获取标识出来的值,然后使用pure来“wrap" IO:

中的结果
main :: IO ()
main = do
    caught_result <- pure (<b>runIdentity</b> (runExceptT badFunction))
    case caught_result of
      Left _ -> putStrLn "caught some error"
      Right _ -> putStrLn "no errors were caught"

但是我们可以在 main 中使用 let … 子句并删除 pure:

main :: IO ()
main = do
    let caught_result = <b>runIdentity</b> (runExceptT badFunction)
    case caught_result of
      Left _ -> putStrLn "caught some error"
      Right _ -> putStrLn "no errors were caught"

, the combination of runIdentity and runExceptT is runExcept :: Except e a -> Either e a,所以我们可以改写为:

main :: IO ()
main = do
    let caught_result = <b>runExcept</b> badFunction
    case caught_result of
      Left _ -> putStrLn "caught some error"
      Right _ -> putStrLn "no errors were caught"

你写

badFunction :: ExceptT Error IO ()
badFunction = throwError Empty

这表明确实如此 IO。但它没有做任何 IO。正如 Willem Van Onsem 指出的那样,一种选择是通过使用 Except 来表示:

badFunction :: Except Error ()

根据 Except 的定义,这等同于

badFunction :: ExceptT Error Identity ()

还有第三种选择:

badFunction :: Monad m => ExceptT Error m ()

这给了你充分的灵活性!

runExcept badFunction :: Either Error ()
runExceptT badFunction :: Monad m => m (Either Error ())

所以如果你选择,你可以写

main :: IO ()
main = do
    caught_result <- runExceptT badFunction
    case caught_result of
      Left _ -> putStrLn "caught some error"
      Right _ -> putStrLn "no errors were caught"

你想的更清楚。