Как отловить (и игнорировать) вызов функции error? - PullRequest
16 голосов
/ 22 ноября 2010

Я удивлен, что нигде не смог найти ответ на этот вопрос.

Я пишу roguelike и использую библиотеку ncurses от hackage, которая является довольно хорошей оболочкой для ncurses.библиотека.Теперь ncurses имеет эту причуду, в которой, если вы попытаетесь написать правый нижний символ, он сделает это, затем попытается переместить курсор к следующему символу, а затем потерпит неудачу, потому что его некуда переместить.Он возвращает значение ошибки, которое вы можете только игнорировать.

Моя проблема в том, что писатель библиотеки haskell ncurses покорно проверяет наличие ошибок во всех вызовах, а когда он есть, он вызывает: error "drawText: и т. Д. И т. Д.. ".

На других языках, таких как c или python, чтобы обойти это, вы вынуждены игнорировать ошибку или ловить и игнорировать исключение, но я не могу понять, каксделай это в хаскеле.Является ли функция ошибок невосстановимой?

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

Ответы [ 2 ]

17 голосов
/ 22 ноября 2010

Вы можете сделать это, используя catch из Control.Exception.Обратите внимание, однако, что для этого вам нужно быть в монаде IO.

13 голосов
/ 22 ноября 2010

error предполагается таким же наблюдаемым, как бесконечный цикл.Вы можете поймать только error в IO, что все равно, что сказать: «Да, можешь, если знаешь магию».Но из действительно хорошей части Haskell, чистого кода, это невозможно восстановить, и поэтому настоятельно рекомендуется не использовать в своем коде, лишь бы вы использовали бесконечный цикл в качестве кода ошибки..

ncurses хамство и заставляет вас делать магию, чтобы исправить это.Я бы сказал, unsafePerformIO будет оправдано, чтобы очистить его.Кроме этого, это во многом совпадает с ответом Пола.

import qualified Control.Exception as Exc

{-# NOINLINE unsafeCleanup #-}
unsafeCleanup :: a -> Maybe a
unsafeCleanup x = unsafePerformIO $ Exc.catch (x `seq` return (Just x)) handler
    where
    handler exc = return Nothing  `const`  (exc :: Exc.ErrorCall)

Затем оберните unsafeCleanup вокруг любого значения, которое может привести к ошибке, чтобы превратить его в Maybe.

...