
On Thu, Feb 10, 2005 at 09:17:17PM +0100, Dmitri Pissarenko wrote:
Hello!
Hello!
I have a list of instances of the ClassifiedImage class, which is defined as follows.
data ClassifiedImage = ClassifiedImage {imageFileName :: String, subjectID :: String} deriving Show
ClassifiedImage is not a class. You use ClassifiedImage both as a type constructor (before =) and as a data constructor (after =).
Attribute imageFileName contains a file name of a certain image. I want to "transform" the list [ClassifiedImage] into a list [(ClassifiedImage, Image)], where Image is content of the file with name imageFileName.
You've used labelled fields. The label imageFileName automatically introduces function imageFileName into scope, with type: imageFileName :: ClassifiedImage -> String
That is, I want to have a routine, which iterates through the list of ClassifiedImages, reads each file (with filename contained in the attribute ClassifiedImage.imageFileName) and stores its content in a variable.
I have already a function, which reads the content of a file.
My idea is to use map for this task:
readClassifiedImages :: [ClassifiedImage] -> [(ClassifiedImage, Image)]
You'll probably have to use a subtly different type for this function: readClassifiedImages :: [ClassifiedImage] -> IO [(ClassifiedImage, Image)]
readClassifiedImages classifiedImages = do return map readerFunc classifiedImages
Note that here you use return with 3 arguments. Most probably not what you want. More about using "map" later.
readerFunc denotes some function, which takes the attribute imageFileName of a ClassifiedImage instance.
I suppose that this readerFunc looks like shown below.
readerFunc :: ClassifiedImage -> (ClassifiedImage, Image) readerFunc classifiedImage = (classifiedImage, fileContent) where fileName = classifiedImageFileName classifiedImage fileContent = readImage fileName
If you wan't to load an image from disk, etc, you'll have to use the IO monad. Thus readerFunc will have an IO type. Also, there is no need to return the ClassifiedImage from readerFunc, unless readerFunc should return a different ClassifiedImage. readerFunc :: ClassifiedImage -> IO Image readerFunc classifiedImage = readFile fileName where fileName = imageFileName classifiedImage
classifiedImageFileName :: ClassifiedImage -> String
classifiedImageFileName = imageFileName
Can I use map for readImage function, which is in the IO domain? If not, what tutorial can help me?
Assuming you have readerFunc :: ClassifiedImage -> IO Image you can use map to construct readClassifiedImages, like this: readClassifiedImages :: [ClassifiedImage] -> IO [(ClassifiedImage, Image)] readClassifiedImages classifiedImages = sequence $ map (\ci -> readerFunc ci >>= \i -> return (ci, i)) classifiedImages but there is already mapM, which can be defined as: mapM f l = sequence (map f l) so you can: readClassifiedImages :: [ClassifiedImage] -> IO [(ClassifiedImage, Image)] readClassifiedImages classifiedImages = mapM (\ci -> readerFunc ci >>= \i -> return (ci, i)) classifiedImages you can also use some syntactic sugar: readClassifiedImages :: [ClassifiedImage] -> IO [(ClassifiedImage, Image)] readClassifiedImages classifiedImages = sequence $ [ do i <- readerFunc ci return (ci, i) | ci <- classifiedImages ] or this way (my preferred notation): readClassifiedImages :: [ClassifiedImage] -> IO [(ClassifiedImage, Image)] readClassifiedImages classifiedImages = (`mapM` classifiedImages) $ \ci -> do i <- readerFunc ci return (ci, i) HTH Best regards Tomasz -- Szukamy programisty C++ i Haskell'a: http://tinyurl.com/5mw4e