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

时间:2018-02-18 22:19:12

标签: haskell

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

check :: FilePath -> IO Bool

来自Main的argv,如下:

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

基本上逻辑是,将IO [Bool]的数组折叠成单个IO Bool并返回它。我使用Monadic版本的Map and Fold,因为我带着IO monad,但是我从类型检查器中得到了很多错误,我无法解释因为引入了占位符,我对此一无所知。

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;
   |

有关如何让typechecker满意的任何线索?

2 个答案:

答案 0 :(得分:5)

foldM的类型是:

GHCi> :t foldM
foldM
  :: (Monad m, Foldable t) => (b -> a -> m b) -> b -> t a -> m b

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

GHCi> :t foldr (&&) True
foldr (&&) True :: Foldable t => t Bool -> Bool

顺便提一下,foldr (&&) True在Prelude中以and的形式提供,因此您只需使用它即可。要将and应用于[Bool]中的IO列表,您可以使用fmap。然后你的do-block的最后一行变成:

fmap and $ mapM check args

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

and <$> mapM check args

(正如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

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

使用来自when的{​​{1}}的更好的表达方式:

Control.Monad

答案 1 :(得分:1)

不确定这是否是唯一的错误,但foldM来电的结果已经是IO Bool;不需要return它。这只会将它包装在另一层monad中。