1

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.

15
  • 4
    An IO String value is not a string. It doesn't make sense to want to put an IO String, for the same reason you wouldn't want to eat a cookbook. Commented Oct 30, 2017 at 16:17
  • I am aware than an IO String is not a string. I am asking how to write an IO String. Commented Oct 30, 2017 at 16:20
  • 1
    @genghiskhan What would you expect to get when you "write" an IO String? Machine code? Assembly instructions? What? Commented Oct 30, 2017 at 16:23
  • 1
    @genghiskhan yes, it is equivalent to a do block. But if you shove a do block in a function argument, it'll always be a monadic action, not a pure value such as the function might accept. Commented Oct 30, 2017 at 16:30
  • 2
    The type of map putStrLn is [String] -> [IO ()], but every statement in your do block must have type IO X for some X (and clearly [IO ()] can't match IO X for any X). However, mapM_ putStrLn :: [String] -> IO (). Commented Oct 30, 2017 at 17:01

1 Answer 1

3

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, i.e. 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"
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.