[Haskell-cafe] Getting an attribute of an object
Tomasz Zielonka
tomasz.zielonka at gmail.com
Thu Feb 10 16:51:02 EST 2005
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
More information about the Haskell-Cafe
mailing list