简体   繁体   中英

Haskell Put IO String

I am trying to read and print the output from the "readProcess" command mapped onto a list of filenames:

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"

Each time I try to map putStrLn onto the mdList, I get this error:

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

I have read many StackOverflow answers that seem to just use putStrLn on an IO String but I am unable to do so. Also, I am new to Haskell so any other tips are also appreciated.

You are using

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

which specializes to

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

The final result, [IO b] is not what we need. That is a list of IO actions, ie the equivalent of a list of non-executed no-arguments imperative functions. Instead, we want a single IO action, whose result is a list of b : that would be IO [b] instead of [IO b] .

The library provides that as well:

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

or, if we don't care about collecting the results

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

The library also provides variants with flipped arguments:

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

So, the original code can be fixed as follows:

import Data.Foldable

files <- readProcess "ls" [] []
for_ files $ \file -> do
    md <- readProcess "mdls" [file] []
    putStrLn md
putStrLn "Complete"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM