Chuck Aguilar
Chuck Aguilar

Reputation: 2048

Troubles with 'Either' in haskell

I'm trying to use 'Either' in Haskell to get the right value. It is usually easy to do, but I'm getting an error, and I don't know what I'm doing wrong.

What I want to do is this:

 cropImage image = do
    resized  <- resizeImage copy        
    newImage <- getImageFromEither resized
    ...

where resized is defined as:

resized :: Either CV.CvException (M.Mat ('CV.S '['CV.D, 'CV.D]) channels depth)

And I want to get M.Mat ('CV.S '['CV.D, 'CV.D]) channels depth

to do it, I use this function:

getImageFromEither eitherImage = fromRight eitherImage

and:

fromRight :: Either a b -> b
fromRight (Left _)  = error "fromRight: Argument takes form 'Left _'"
fromRight (Right x) = x

And I thought it should work. But I get this error:

    Couldn't match kind ‘*’ with ‘CV.DS *'
    When matching types
      m :: * -> *
      M.Mat ('CV.S '['CV.D, 'CV.D]) channels :: CV.DS * -> *
    Expected type: Either CV.CvException (m t0)
      Actual type: Either
                     CV.CvException (M.Mat ('CV.S '['CV.D, 'CV.D]) channels depth)
    Relevant bindings include
      resized :: Either
                   CV.CvException (M.Mat ('CV.S '['CV.D, 'CV.D]) channels depth)
        (bound at src/CropImage.hs:25:9)
      copy :: M.Mat ('CV.S '[height, width]) channels depth
        (bound at src/CropImage.hs:32:17)
      image :: M.Mat ('CV.S '[height, width]) channels depth
        (bound at src/CropImage.hs:24:11)
      cropImage :: M.Mat ('CV.S '[height, width]) channels depth
                   -> m (Either
                           CV.CvException (M.Mat ('CV.S '['CV.D, 'CV.D]) channels depth))
        (bound at src/CropImage.hs:24:1)
    In the first argument of ‘getImageFromEither’, namely ‘resized’
    In a stmt of a 'do' block: newImage <- getImageFromEither resized

I don't have an idea what's wrong. I see the code right, but I'm blind with the error.

Upvotes: 0

Views: 357

Answers (1)

chi
chi

Reputation: 116139

You likely want

cropImage image = do
    resized  <- resizeImage copy        
    let newImage = getImageFromEither resized
    ...

Remember that <- is used to run monadic actions, and let .. = .. is used to define pure values. Here, getImageFromEither has not a monadic return type -- it does not perform any action in the monad, it is a plain, regular function.

Also consider the possibility of handling both cases explicitly:

cropImage image = do
    resized  <- resizeImage copy
    case resized of
      Left err -> error ("resize failed: " ++ show err)
      Right newImage -> do
         ...

This also allows you to handle the error more gracefully, e.g. by reporting it to the user. Using error or a partial function like your getImageFromEither is not generally considered good style. Handling errors by crashing is convenient in the short term, but eventually you'll likely want that error to be handled properly.

Upvotes: 5

Related Questions