n g
n g

Reputation: 1

couldn't match type [] with IO

my program is supposed to go through all of the files in a given directory, and append a counter to the content of each file with the extension ".vm". however, it has an error "couldn't mach type [] with IO" in the append. if anyone can help i'll be geatfull

my code:

import System.IO
import qualified Data.ByteString.Lazy.Char8 as B
import Control.Applicative
import Data.List
import System.Directory
import System.FilePath

main = do
    files <- getDirectoryContents "c:/program file"
    let filtered = filter ( vmExtention ) files
    [ appendFile x y| x<-filtered, y <- [0..] ]
    print filtered
    print files

vmExtention :: FilePath-> Bool
vmExtention s = 
    if ( takeExtension s )== ".vm" then True else False

Upvotes: 0

Views: 277

Answers (3)

Zeta
Zeta

Reputation: 105886

[ appendFile x y| x<-filtered, y <- [0..] ]

That's a stray list comprehension of type [IO ()] if appendFile x y was valid (it's not). You have to use sequence or similar:

sequence [ appendFile x y| x<-filtered, y <- [0..] ]

However, this won't work, since y must be a String, and [0..] is an infinite list, so you would end up with

appendFile x 0
appendFile x 1
appendFile x 2
appendFile x 3
...

You want something along

sequence [appendFile file (show counter) | (file, counter) <- zip filtered [0..]]

Upvotes: 3

Michiel Borkent
Michiel Borkent

Reputation: 34810

import System.IO
import qualified Data.ByteString.Lazy.Char8 as B
import Control.Applicative
import Data.List
import System.Directory
import System.FilePath
import Debug.Trace

debug = flip trace

main = do
    let path = "/tmp/test"
    files <- getDirectoryContents path
    let filtered = filter ( vmExtention ) files
    let filteredWithIndex = zip filtered [0..]
    sequence_ [ appendFile' (path </> fp) (show i) | (fp,i) <- filteredWithIndex ]

appendFile' fp s =
  -- note that the path was relative but is now fixed
  appendFile fp s `debug` ("filepath: " ++ fp)

vmExtention :: FilePath-> Bool
vmExtention s = 
    takeExtension s == ".vm"

Upvotes: 0

Simon Courtenage
Simon Courtenage

Reputation: 416

In your code, files is a list of IO actions ([IO ()]), so to execute the IO actions in the list, you can simply call sequence files. However, you also need to correct the list comprehension - as it stands, it will attempt to add all integers in the range [0..] to the end of the first file (the ranges in the list comprehension are nested from left to right, i.e,. given x<-A, y<-B, for each x, we take a y from B until B is exhausted, before taking the next x). A better list comprehension would be

let files = [appendFile (path </> x) (show y) | zip filtered [0..] ]

Note you also need to add the path to the beginning of the filename (I added let path = "c:\program file" to the beginning of the main function), and you need to show the integer to turn it into a string for appendFile.

Upvotes: 0

Related Questions