doesFileExist "foo.txt"
- IO Bool
, что означает, что его результат зависит от состояния внешнего мира.
Вы находитесь на правильном пути с map doesFileExist files
- это выражение вернет [IO Bool]
или список выражений, зависящих от мира. Фактически необходимо выражение IO
, содержащее список bools. Вы можете получить это с помощью sequence
:
sequence :: Monad m => [m a] -> m [a]
или, так как вы используете только последовательность/карты, функции mapM
помощника:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM f xs = sequence (map f xs)
Давайте вернемся к коду. Вот версия с использованием mapM
с комментариями:
import System.Directory
-- When figuring out some unfamiliar libraries, I like to use type annotations
-- on all top-level definitions; this will help you think through how the types
-- match up, and catch errors faster.
allFilesPresent :: [String] -> IO Bool
-- Because allFilesPresent returns a computation, we can use do-notation to write
-- in a more imperative (vs declarative) style. This is sometimes easier for students
-- new to Haskell to understand.
allFilesPresent files = do
-- Run 'doesFileExist' tests in sequence, storing the results in the 'filesPresent'
-- variable. 'filesPresent' is of type [Bool]
filesPresent <- mapM doesFileExist files
-- The computation is complete; we can use the standard 'and' function to join the
-- list of bools into a single value.
return (and filesPresent)
Альтернативная версия использует более декларативный синтаксис; это, вероятно, что опытный программист на Haskell написать:
allFilesPresent :: [String] -> IO Bool
allFilesPresent = fmap and . mapM doesFileExist
Следует отметить, что 'foldr (&&) true' функция Prelude.and. – HaskellElephant
Я настоятельно рекомендую прочитать http://learnyouahaskell.com/input-and-output. Затем вы можете прочитать некоторые другие главы о функциях, аппликациях, моноидах и монадах. Очень нежное и постепенное введение в эти темы. – Daniel