Getting an attribute of an object

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 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. 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)] readClassifiedImages classifiedImages = do return map readerFunc classifiedImages 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 classifiedImageFileName :: ClassifiedImage -> String In order for this function to work, I need to define classifiedImageFileName, which "returns" the imageFileName attribute of an instance of ClassifiedImage class. How can I define this function? Can I use map for readImage function, which is in the IO domain? If not, what tutorial can help me? Thanks in advance Dmitri Pissarenko -- Dmitri Pissarenko Software Engineer http://dapissarenko.com

Can I use map for readImage function, which is in the IO domain? If not, what tutorial can help me?
Sorry, by "IO domain" I mean "IO monad". Dmitri Pissarenko -- Dmitri Pissarenko Software Engineer http://dapissarenko.com

On 10 Feb 2005, at 20:17, Dmitri Pissarenko wrote:
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
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.
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)] readClassifiedImages classifiedImages = do return map readerFunc classifiedImages
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
classifiedImageFileName :: ClassifiedImage -> String
In order for this function to work, I need to define classifiedImageFileName, which "returns" the imageFileName attribute of an instance of ClassifiedImage class.
This is called a selector function. Haskell defines one automatically with the same name as the field. imageFileName is a function ClassifiedImage -> String. (ClassifiedImage is not a class, it's a datatype, by the way)
How can I define this function?
Can I use map for readImage function, which is in the IO domain? If not, what tutorial can help me?
If you're happy to replace Image with IO image, then that will be fine. Jules

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

Thanks for the help! -- Dmitri Pissarenko Software Engineer http://dapissarenko.com

Hello! I have now another problem. I have a function readClassifiedImages :: [ClassifiedImage] -> [IO (ClassifiedImage, Image)] readClassifiedImages classifiedImages = map readClassifiedImagesSelector classifiedImages data ClassifiedImage = ClassifiedImage {imageFileName :: String, subjectID :: String} deriving Show I have another function, which should transform [IO (ClassifiedImage, Image)] to [IO Image]. For a certain operation, I need just the images without the information contained in the data type ClassifiedImage. So I defined following function: getImages :: [IO (ClassifiedImage, Image)] -> [IO Image] getImages classifiedImages = map snd classifiedImages First argument of it has the same type as the "return value" of function readClassifiedImages. Then I created following program. <program> module ExperimentalYaleDb where import Lik main = do let trainingSet = [(ClassifiedImage "../data-test/yalefaces- pgm/subject01.centerlight.pgm" "subject01"), (ClassifiedImage "../data-test/yalefaces- pgm/subject02.centerlight.pgm" "subject02"), (ClassifiedImage "../data-test/yalefaces- pgm/subject03.centerlight.pgm" "subject03"), (ClassifiedImage "../data-test/yalefaces- pgm/subject04.centerlight.pgm" "subject04"), (ClassifiedImage "../data-test/yalefaces- pgm/subject05.centerlight.pgm" "subject05"), (ClassifiedImage "../data-test/yalefaces- pgm/subject06.centerlight.pgm" "subject06"), (ClassifiedImage "../data-test/yalefaces- pgm/subject07.centerlight.pgm" "subject07"), (ClassifiedImage "../data-test/yalefaces- pgm/subject08.centerlight.pgm" "subject08"), (ClassifiedImage "../data-test/yalefaces- pgm/subject09.centerlight.pgm" "subject09"), (ClassifiedImage "../data-test/yalefaces- pgm/subject10.centerlight.pgm" "subject10")] -- read images from files classifiedImagesWithData <- (readClassifiedImages trainingSet) -- fetch images only from classifiedImagesWithData allImages <- (getImages classifiedImagesWithData) return 0 </program> When I try to run this program in GHCi, I'm getting this error message <error> C:\dapWork\lik\sw\src>startghci Lik.hs:14: Couldn't match `(a, IO Image)' against `IO (ClassifiedImage, Image)' Expected type: [(a, IO Image)] Inferred type: [IO (ClassifiedImage, Image)] In the second argument of `map', namely `classifiedImages' In the definition of `getImages': getImages classifiedImages = map snd classifiedImages Failed, modules loaded: HUnit, HUnitText, HUnitBase, HUnitLang. *HUnit> </error> where "Lik.hs:14" denotes the line getImages classifiedImages = map snd classifiedImages How can I solve this problem? TIA Dmitri Pissarenko -- Dmitri Pissarenko Software Engineer http://dapissarenko.com

Hello! I could now find the place, where an error occurs. In my program, I have following statement: do ... classifiedImagesWithData <- (readClassifiedImages trainingSet) readClassifiedImages is defined as follows: readClassifiedImages :: [ClassifiedImage] -> [IO (ClassifiedImage, Image)] readClassifiedImages classifiedImages = (map readClassifiedImagesSelector classifiedImages) When I load the file with the definition of this function into GHCi and then type in ":t readClassifiedImages", I get the output readClassifiedImages :: [ClassifiedImage] -> [IO (ClassifiedImage, Image)] which is what I want. However, when in the program I insert the statement classifiedImagesWithData :: [IO (ClassifiedImage, Image)] so that it becomes do ... classifiedImagesWithData <- (readClassifiedImages trainingSet) classifiedImagesWithData :: [IO (ClassifiedImage, Image)] -- error line I get the error <error> ExperimentalYaleFaceDb.hs:28: Couldn't match `[IO (ClassifiedImage, Image)]' against `IO (ClassifiedImage, Image)' Expected type: [IO (ClassifiedImage, Image)] Inferred type: IO (ClassifiedImage, Image) When checking the type signature of the expression: classifiedImagesWithData :: [IO (ClassifiedImage, Image)] In a 'do' expression: classifiedImagesWithData :: [IO (ClassifiedImage, Image)] </error> Line 28 is the line marked with "error line" in the code snippet above. I don't understand why this typing error occurs even though the readClassifiedImages definition seems to be correct (at least, GHCi loads the file, where it is located without complaints). Any hint is highly appreciated. Best regards Dmitri Pissarenko -- Dmitri Pissarenko Software Engineer http://dapissarenko.com

On 11 Feb 2005, at 19:09, Dmitri Pissarenko wrote:
readClassifiedImages :: [ClassifiedImage] -> [IO (ClassifiedImage, Image)]
which is what I want.
However, when in the program I insert the statement
classifiedImagesWithData :: [IO (ClassifiedImage, Image)]
so that it becomes
do ... classifiedImagesWithData <- (readClassifiedImages trainingSet) classifiedImagesWithData :: [IO (ClassifiedImage, Image)] -- error line
Inferred type: IO (ClassifiedImage, Image)
Well, can you explain why you are using do notation at all? In do notation, the <- form, informally speaking, 'strips off' a Monad. Because the type of readClassifiedImages is a list, then haskell knows you are using the list Monad, so the effect is to work within the list Monad. It may be you'd profit from reading some of the Monad tutorials out there. Jules

Hello! Sorry that I bother you again with my problem.
It may be you'd profit from reading some of the Monad tutorials out there.
I followed your advice and read the "All about monads" tutorial. After I've done that I could fix one problem. But now there is another one. In the main program, there is following piece of code <code-snippet> let classifiedImagesWithData = ((return trainingSet) >>= readClassifiedImages) let allImages = (getImages classifiedImagesWithData) </code-snippet> Signatures of readClassifiedImages and getImages are readClassifiedImages :: [ClassifiedImage] -> [IO (ClassifiedImage, Image)] getImages :: [(ClassifiedImage, Image)] -> [Image] readClassifiedImages does some file I/O, so it is OK when its result is in the IO monad. getImages does not do any IO related stuff, so I declared it without the IO monad. The line let allImages = (getImages classifiedImagesWithData) of the above code snippet leads to following error: <error> ExperimentalYaleFaceDb.hs:43: Couldn't match `(ClassifiedImage, Image)' against `IO (ClassifiedImage, Image)' Expected type: [(ClassifiedImage, Image)] Inferred type: [IO (ClassifiedImage, Image)] In the first argument of `getImages', namely `classifiedImagesWithData' In the definition of `allImages': allImages = (getImages classifiedImagesWithData) Failed, modules loaded: TestLik, Lik, HUnit, HUnitText, HUnitBase, HUnitLang. </error> Is there a way to fix this problem apart from changing signature of getImage? Thanks in advance Dmitri Pissarenko -- Dmitri Pissarenko Software Engineer http://dapissarenko.com

Perhaps try:
do ...
ciwd <- sequence classifiedImagesWithData
let allImages = (getImages ciwd)
...
as it seems like you're trying to gave getImages act on a value of
type [IO (ClassifiedImage, Image)]. Applying sequence to
classifiedImagesWithData will turn it into an IO [(ClassifiedImage,
Image)] by doing the natural thing, from which you can pull out the
list to apply getImages to.
- Cale
On Sat, 12 Feb 2005 21:10:31 +0100, Dmitri Pissarenko
Hello!
Sorry that I bother you again with my problem.
It may be you'd profit from reading some of the Monad tutorials out there.
I followed your advice and read the "All about monads" tutorial. After I've done that I could fix one problem.
But now there is another one.
In the main program, there is following piece of code
<code-snippet> let classifiedImagesWithData = ((return trainingSet) >>= readClassifiedImages)
let allImages = (getImages classifiedImagesWithData) </code-snippet>
Signatures of readClassifiedImages and getImages are
readClassifiedImages :: [ClassifiedImage] -> [IO (ClassifiedImage, Image)] getImages :: [(ClassifiedImage, Image)] -> [Image]
readClassifiedImages does some file I/O, so it is OK when its result is in the IO monad.
getImages does not do any IO related stuff, so I declared it without the IO monad.
The line
let allImages = (getImages classifiedImagesWithData)
of the above code snippet leads to following error:
<error> ExperimentalYaleFaceDb.hs:43: Couldn't match `(ClassifiedImage, Image)' against `IO (ClassifiedImage, Image)' Expected type: [(ClassifiedImage, Image)] Inferred type: [IO (ClassifiedImage, Image)] In the first argument of `getImages', namely `classifiedImagesWithData' In the definition of `allImages': allImages = (getImages classifiedImagesWithData) Failed, modules loaded: TestLik, Lik, HUnit, HUnitText, HUnitBase, HUnitLang. </error>
Is there a way to fix this problem apart from changing signature of getImage?
Thanks in advance
Dmitri Pissarenko -- Dmitri Pissarenko Software Engineer http://dapissarenko.com
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Hello! Thanks for your answer!
Perhaps try:
do ... ciwd <- sequence classifiedImagesWithData let allImages = (getImages ciwd) ...
as it seems like you're trying to gave getImages act on a value of type [IO (ClassifiedImage, Image)]. Applying sequence to classifiedImagesWithData will turn it into an IO [(ClassifiedImage, Image)] by doing the natural thing, from which you can pull out the list to apply getImages to.
I've tried that and wrote <code-snippet> do... let classifiedImagesWithData = ((return trainingSet) >>= readClassifiedImages) ciwd <- (sequence classifiedImagesWithData) let allImages = (getImages ciwd) </code-snippet> Now, I get the error <error> Compiling ExperimentalYaleDb ( ExperimentalYaleFaceDb.hs, interpreted ) ExperimentalYaleFaceDb.hs:41: Couldn't match `[]' against `IO' Expected type: [[a]] Inferred type: [IO (ClassifiedImage, Image)] In the first argument of `sequence', namely `classifiedImagesWithData' In a 'do' expression: ciwd <- (sequence classifiedImagesWithData) Failed, modules loaded: TestLik, Lik, HUnit, HUnitText, HUnitBase, HUnitLang. </error> at line ciwd <- (sequence classifiedImagesWithData) Are there any other options? Thanks in advance Dmitri Pissarenko PS: Maybe the error is rooted in code parts other than those given here. In the attachment there is the code of the main program (ExperimentalYaleFaceDb.hs) and the function definitions (Lik.hs). -- Dmitri Pissarenko Software Engineer http://dapissarenko.com

Am Sonntag, 13. Februar 2005 10:16 schrieb Dmitri Pissarenko:
Hello!
Thanks for your answer!
I've tried that and wrote
<code-snippet> do... let classifiedImagesWithData = ((return trainingSet) >>= readClassifiedImages) ciwd <- (sequence classifiedImagesWithData) let allImages = (getImages ciwd) </code-snippet>
Now, I get the error
<error> Compiling ExperimentalYaleDb ( ExperimentalYaleFaceDb.hs, interpreted )
ExperimentalYaleFaceDb.hs:41: Couldn't match `[]' against `IO' Expected type: [[a]] Inferred type: [IO (ClassifiedImage, Image)] In the first argument of `sequence', namely `classifiedImagesWithData' In a 'do' expression: ciwd <- (sequence classifiedImagesWithData) Failed, modules loaded: TestLik, Lik, HUnit, HUnitText, HUnitBase, HUnitLang. </error>
at line
ciwd <- (sequence classifiedImagesWithData)
Are there any other options?
Thanks in advance
Dmitri Pissarenko
PS: Maybe the error is rooted in code parts other than those given here. In the attachment there is the code of the main program (ExperimentalYaleFaceDb.hs) and the function definitions (Lik.hs).
The error is in the code line above, you can't write trainingSet :: [ClassifiedImage] by itself in a do statement. With -fglasgow-exts, you could write let (trainingSet :: [ClassifiedImage]) = ..., though there's no need for this type signature. Thus, ghci had no more complaints.
-- Dmitri Pissarenko Software Engineer http://dapissarenko.com
HTH, Daniel

The error is in the code line above, you can't write trainingSet :: [ClassifiedImage] by itself in a do statement.
Thanks for your advice! Now it works. Best regards Dmitri Pissarenko -- Dmitri Pissarenko Software Engineer http://dapissarenko.com
participants (5)
-
Cale Gibbard
-
Daniel Fischer
-
Dmitri Pissarenko
-
Jules Bean
-
Tomasz Zielonka