4
\$\begingroup\$

I have a function that returns size of an image IO (Maybe (Int, Int)) It would be nice to convert it to float tuple beautifully.

I am sure there must be a better way than what I currently have:

data Vec2D = Vec2D Float Float

getImageSize :: FilePath -> IO (Maybe (Int, Int))
getImageSize path = do
    img <- readImage path
    case img of
        Left _ -> return Nothing
        Right img' -> return (go img')
    where
        go :: DynamicImage -> Maybe (Int, Int)
        go (ImageRGB8 (Image w h _)) = Just (w, h)
        go (ImageRGBA8 (Image w h _)) = Just (w, h)
        go _ = Nothing

getImageSizeVec :: FilePath -> IO Vec2D
getImageSizeVec path = do
    res <- getImageSize path
    let dims = fromMaybe (0, 0) res
    return $ Vec2D (fromIntegral (fst dims)) (fromIntegral (snd dims)) 
\$\endgroup\$
2
\$\begingroup\$
  1. I do not understand what benefit you get from the conversion to float
  2. I would advise you to not mix - IO with the mostly pure calculation you have

so let us look at your code (minus the IO)

getImageSize :: DynamicImage -> Maybe (Int, Int)
getImageSize (ImageRGB8  (Image w h _)) = Just (w, h)
getImageSize (ImageRGBA8 (Image w h _)) = Just (w, h)
getImageSize _ = Nothing

but readImage already has a more useful return type than Maybe it has an Either String which is giving you error messages instead of Nothing so we can adjust.

getImageSize :: DynamicImage -> Either String (Int, Int)
getImageSize (ImageRGB8  (Image w h _)) = Right (w, h)
getImageSize (ImageRGBA8 (Image w h _)) = Right (w, h)
getImageSize _ = Left "Image type neither ImageRGB8 or ImageRGBA8"

this section could be improved a bit - also working on pure data

sizeToVec :: (Int,Int) -> Vec2D
sizeToVec (x,y) = Vec2D (fromIntegral x) (fromIntegral y)

you can then use those with the many mechanisms haskell provides you:

 readImage path :: IO (Either String DynamicImage)
 getImageSize :: DynamicImage -> Either String (Int, Int)
 sizeToVec :: (Int,Int) -> Vec2D

the last two you can combine à la

fmap sizeToVec (getImageSize img) -- or fmap sizeToVec . getImageSize

and the first two

doStuff = do eitherImg <- readImg mypathtoimg
             return $ do size <- getImageSize
                         sizeToVec size

or

doStuff = do eitherImg <- readImg mypathtoimg
             return (getImageSize eitherImg >>= sizeToVec)

or even shorter

doStuff = readImg mypathtoimg >>= (getImageSize >>= sizeToVec)

doStuff = readImg path >>= fmap sizeToVec . getImageSize

if I am not mistaken (I have no haskell env on this machine, therefore this code is untested - sorry)

\$\endgroup\$
  • \$\begingroup\$ sizeToVec has the wrong type for >>=. Perhaps you meant readImg path >>= fmap sizeToVec . getImageSize? \$\endgroup\$ – Zeta Jan 17 '16 at 15:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.