haskell - IO Monad 中的链式 if/else 语句

标签 haskell monads

我想知道是否有一种惯用的方法可以在 IO Monad 中以命令式语言编写类似于链式 if/else 语句的控制代码。

所以在像 Python 这样的语言中,我通常会纠正这样的事情:

if οs.path.isdir(fname):
    # do whatever
elif os.path.isfile(fname):
    # ...
else:
    # ...

我在 Haskell 中能想到的最好的方法如下:
isf <- doesFileExist path
isd <- if isf then return False else doesDirectoryExist path
case (isf, isd) of
    (True,  _)      -> return ...
    (_,     True)   -> return ...
    _               -> return ...

哪个不太好,我想知道是否有更好的方法来写这种东西。

另外,为了验证我的理解:if isf参与isd <- ...在 IO Monad 的情况下是必需的,如果您不想总是同时执行这两个操作。我的猜测是,在其他 Monad(懒惰的 Monad?)中,这不是必需的,因为 isd将被懒惰地评估。

编辑

根据第一条评论,我得出以下结论:
firstMatchM :: (Monad m) => a -> [(a -> m Bool, b)] -> b -> m b
firstMatchM arg [] def   = return def
firstMatchM arg ((check,x):xs) def = do
    t <- check arg
    if t then return x else firstMatchM arg xs def

doFirstM :: (Monad m) => a -> [(a -> m Bool, a -> m b)] -> (a -> m b) -> m b
doFirstM arg acts def = do
    fm <- firstMatchM arg acts def
    fm arg

handlePath2 path = doFirstM path
   [( \p -> doesFileExist p,
         \p ->  return "file"
   ),(\p -> doesDirectoryExist p,
         \p -> return "dir"
   )] $ \p -> return "Error"

这类似于@chi的第二个建议,我更喜欢ifM ,因为它更接近命令式版本。

最佳答案

如果我们不想涉及 monad 转换器,一个基本的选择是滚动我们自己的 monad if :

ifM :: Monad m => m Bool -> m a -> m a -> m a
ifM act t e = do
  b <- act
  if b then t else e

然后代码结构类似于命令式语言中的代码结构:
test :: IO String
test = ifM anAction (do
          putStrLn "branch a"
          return "a")
       $ ifM otherAction (do
          putStrLn "branch b"
          return "b")
       $ return "none"

在哪里 anAction, otherAction :: IO Bool .

或者,使用类似的东西
ifChain :: [(IO Bool, IO a)] -> IO a -> IO a
ifChain [] e = e
ifChain ((g, a) : acts) e = do
   b <- g
   if b then a else ifChain acts e

关于haskell - IO Monad 中的链式 if/else 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33593007/

相关文章:

unit-testing - 模拟 IO 操作 : getArgs and putStrLn

c++ - 从 C++ 到 Haskell 类和状态

haskell - 在 Haskell 中将 1 到 1,000,000 相加会导致堆栈溢出。引擎盖下发生了什么?

haskell - `readIORef`怎么会是阻塞操作

haskell - 使用 HaskellDB 取消映射表记录的基本示例

web-applications - Heist:如何将子模板的动态列表插入到模板中?

haskell - 链接状态 Monad

haskell - 如何将文本转换为字节串生成器?

haskell - IO Monad 记录更新失败?

haskell - 为什么我可以在不提供 monad 的情况下调用 monadic 函数?