2016-09-21 3 views
0

Я пытаюсь использовать «Либо» в Haskell, чтобы получить справа значение. Обычно это легко сделать, но я получаю сообщение об ошибке, и я не знаю, что я делаю неправильно.Смуты с «Либо» в haskell

То, что я хочу сделать это:

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 

У меня нет идеи, что не так. Я вижу код правильно, но я слеп с ошибкой.

+0

Если 'resized' имеет тип' Либо CV.CvException (M.Mat ('CV.S' ['CV.D,' CV.D]) 'вы говорите, что' resizeImage' возвращает 'Either e (Либо CV.CvException (M.Mat ('CV.S' ['CV.D,' CV.D]))? Или же 'resizeImage' возвращает' Либо CV.CvException (M.Mat ('CV.S '[' CV.D, 'CV.D]) '? В этом случае' resized' является '(M.Mat (' CV.S '[' CV.D, 'CV.D])' – Lee

+0

@Lee Спасибо за ваш ответ. 'ResizeImage' возвращает' либо CV.CvException (M.Mat ('CV.S' ['CV.D,' CV.D]). Но, как вы можете видеть в сообщении об ошибке , resized является «Либо CV.CvException (M.Mat (« CV.S »['CV.D,' CV.D])' Не так ли? –

+0

Если у вас есть выражение 'x' типа' Либо ea', то внутри 'do' нотации, в' v <- x', 'v' имеет тип' a'. Таким образом, это означает, что 'resized' имеет тип' M.Mat ('CV.S' ['CV.D, 'CV.D] ', и вам не нужно использовать' getImageFromEither'. Работает ли он, если вы используете 'newImage <- resizeImage copy'? – Lee

ответ

5

Вы, вероятно, хотите

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

Помните, что <- используется для запуска монадических действий, и let .. = .. используется для определения чистых значений. Здесь getImageFromEither не имеет монадического типа возврата - он не выполняет никаких действий в монаде, это простая регулярная функция.

Также рассмотреть возможность обработки обоих случаях явно:

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

Это также позволяет обрабатывать ошибку более изящно, например сообщая об этом пользователю. Использование error или частичная функция, такая как ваш getImageFromEither, обычно не считается хорошим стилем. Обработка ошибок при сбое удобна в краткосрочной перспективе, но в конечном итоге вы, скорее всего, захотите, чтобы эта ошибка обрабатывалась должным образом.

+0

Спасибо!Он работает отлично. Просто вещь. Я хотел бы использовать второй способ, но он не работает для меня, поскольку мне нужно _return newImage_ в какое-то время. Когда я пишу 'Right newImage -> do', а затем' return newImage', он говорит 'Не может соответствовать ожидаемому типу 'IO()' с фактическим типом 'M.Mat (' CV.S '[' CV.D, 'CV.D]) channel depth'' Итак, как я могу вернуть _newImage_? –

+0

'return newImage' выглядит правильно ... вы уверены, что вы объявили' cropImage' возвращать 'IO (M.Mat ...)', а не 'IO()'? Интересно, почему ожидаемый тип 'IO()' там в соответствии с ошибкой. – chi

+0

Я могу 'return newImage', если я напишу' let newImage = ... ', но я не могу его вернуть, если я напишу его внутри' case ... of ... 'Я не знаю почему. –

Смежные вопросы