1

我正在尝试读取并打印映射到文件名列表的“readProcess”命令的输出:

files <- readProcess "ls" [] []
let mdList = map ( \file -> do
    md <- readProcess "mdls" [file] []
    return md ) $ splitOn "\n" files in
    map (\md -> putStrLn md) mdList
putStrLn "Complete"

每次我尝试将 putStrLn 映射到 mdList 时,都会收到此错误:

Couldn't match type ‘IO String’ with ‘[Char]’

我已经阅读了许多似乎只是在 IO 字符串上使用 putStrLn 的 StackOverflow 答案,但我无法这样做。另外,我是 Haskell 的新手,因此也感谢任何其他提示。

4

1 回答 1

3

您正在使用

map :: (a -> b) -> [a] -> [b]

专门针对

map :: (a -> IO b) -> [a] -> [IO b]

最终的结果,[IO b]并不是我们所需要的。那是一个IO动作列表,即相当于一个未执行的无参数命令式函数的列表。相反,我们想要一个动作 IO,其结果是一个b:列表,IO [b]而不是[IO b].

该库还提供:

mapM :: (a -> IO b) -> [a] -> IO [b]

或者,如果我们不关心收集结果

mapM_ :: (a -> IO b) -> [a] -> IO ()

该库还提供了带有翻转参数的变体:

for  :: [a] -> (a -> IO b) -> IO [b]
for_ :: [a] -> (a -> IO b) -> IO ()

因此,可以将原始代码固定如下:

import Data.Foldable

files <- readProcess "ls" [] []
for_ files $ \file -> do
    md <- readProcess "mdls" [file] []
    putStrLn md
putStrLn "Complete"
于 2017-10-30T21:15:46.093 回答