使用IO [Bool]不正确地使用foldM进行arg解析

rau*_*ted 1 haskell

我是Haskell的新手,我正在尝试映射检查文件是否存在的检查函数,如下所示:

check :: FilePath -> IO Bool

来自Main的argv,如下:

main :: IO Bool
main = do {
    args <- getArgs;
    return $ foldM (&&) True $ mapM check args;
}
Run Code Online (Sandbox Code Playgroud)

基本上逻辑是,将IO [Bool]的数组折叠成单个IO Bool并返回它.我使用地图的单子版本和折叠,因为我身边携带IO单子,但我得到了很多来自typechecker,我不能因为占位符真正破译错误的介绍,我什么都不知道关于.

src/Main.hs:15:9: error:
    • Couldn't match type ‘m0 Bool’ with ‘Bool’
      Expected type: IO Bool
        Actual type: IO (m0 Bool)
    • In a stmt of a 'do' block:
        return $ foldM (&&) True $ mapM check args
      In the expression:
        do args <- getArgs
           return $ foldM (&&) True $ mapM check args
      In an equation for ‘main’:
          main
            = do args <- getArgs
                 return $ foldM (&&) True $ mapM check args
   |
15 |         return $ foldM (&&) True $ mapM check args;
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Main.hs:15:24: error:
    • Couldn't match type ‘Bool’ with ‘m0 Bool’
      Expected type: Bool -> Bool -> m0 Bool
        Actual type: Bool -> Bool -> Bool
    • In the first argument of ‘foldM’, namely ‘(&&)’
      In the expression: foldM (&&) True
      In the second argument of ‘($)’, namely
        ‘foldM (&&) True $ mapM check args’
   |
15 |         return $ foldM (&&) True $ mapM check args;
   |                        ^^^^

src/Main.hs:15:36: error:
    • Couldn't match type ‘[Bool]’ with ‘Bool’
      Expected type: IO Bool
        Actual type: IO [Bool]
    • In the second argument of ‘($)’, namely ‘mapM check args’
      In the second argument of ‘($)’, namely
        ‘foldM (&&) True $ mapM check args’
      In a stmt of a 'do' block:
        return $ foldM (&&) True $ mapM check args
   |
15 |         return $ foldM (&&) True $ mapM check args;
   |
Run Code Online (Sandbox Code Playgroud)

任何线索如何让typechecker开心?

dup*_*ode 5

类型foldM是:

GHCi> :t foldM
foldM
  :: (Monad m, Foldable t) => (b -> a -> m b) -> b -> t a -> m b
Run Code Online (Sandbox Code Playgroud)

你给它的二进制函数应该在一些monad中产生monadic结果m(在你的情况下,m将是IO).(&&)但是,不产生一元结果.这意味着你不需要foldM这里:普通折叠会做:

GHCi> :t foldr (&&) True
foldr (&&) True :: Foldable t => t Bool -> Bool
Run Code Online (Sandbox Code Playgroud)

顺便提一下,foldr (&&) True在Prelude中and可以使用,因此您可以使用它.要申请and加入您的[Bool]清单IO,您可以使用fmap.你的do-block的最后一行然后变成:

fmap and $ mapM check args
Run Code Online (Sandbox Code Playgroud)

或者,使用(<$>),这是中缀拼写fmap:

and <$> mapM check args
Run Code Online (Sandbox Code Playgroud)

(正如Sebastian Redl所指出的那样,这return是不必要的,因为已经and <$> mapM check args是类型IO Bool了.)


顺便说一下,请注意,给出main类型IO Bool不会达到预期效果 - 返回值将main被丢弃.要返回错误退出代码,您可以使用,例如exitFailure:

argsOK <- and <$> mapM check args
if not argsOK
    then exitFailure
    else return ()
-- rest of your do-block
Run Code Online (Sandbox Code Playgroud)

(return ()这里只是一个无所事事的占位符.)

该表达的更好的方法是使用whenControl.Monad:

argsOK <- and <$> mapM check args
when (not argsOK) exitFailure
-- rest of your do-block 
Run Code Online (Sandbox Code Playgroud)