在haskell中遇到'Either'的麻烦

时间:2016-09-21 09:49:30

标签: haskell

我正在尝试在Haskell中使用'Either'来获取正确的值。这通常很容易,但我收到了一个错误,我不知道我做错了什么。

我想做的是:

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

其中resized定义为:

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

我希望得到M.Mat ('CV.S '['CV.D, 'CV.D]) channels depth

要做到这一点,我使用这个功能:

getImageFromEither eitherImage = fromRight eitherImage

和:

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

我认为它应该有效。但是我得到了这个错误:

    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

我不知道出了什么问题。我看到代码正确,但我对错误视而不见。

1 个答案:

答案 0 :(得分:5)

你可能想要

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

请记住,<-用于运行monadic操作,let .. = ..用于定义纯值。这里,getImageFromEither没有monadic返回类型 - 它不会在monad中执行任何操作,它是一个普通的常规函数​​。

还要考虑明确处理这两种情况的可能性:

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

这也允许您更优雅地处理错误,例如通过向用户报告。使用error或部分函数(例如getImageFromEither)通常不会被认为是好的风格。通过崩溃处理错误在短期内很方便,但最终你可能希望正确处理错误。