Как поймать (и игнорировать) вызов функции ошибки?
Я удивлен, что не мог найти ответа на все это.
Я пишу roguelike, и я использую библиотеку ncurses из hackage, которая является довольно хорошей оболочкой вокруг библиотеки ncurses. Теперь ncurses имеет эту причуду, где, если вы попытаетесь написать нижний правый символ, он делает это, затем он пытается переместить курсор на следующий символ, а затем он терпит неудачу, потому что туда некуда его переместить. Он возвращает значение ошибки, которое можно игнорировать.
Моя проблема заключается в том, что писатель библиотеки haskell ncurses добросовестно проверяет наличие ошибок во всех вызовах, а когда есть один, он вызывает: "drawText: etc и т.д.".
В других языках, таких как c или python, чтобы обойти это, вы вынуждены игнорировать ошибку или улавливать и игнорировать исключение, но для жизни я не могу понять, как это сделать в haskell. Неустранимая функция ошибки?
Я буду модифицировать библиотеку локально, чтобы не проверять наличие ошибок в этой функции, если это необходимо, но я ненавижу это делать. Я также открываю любое обходное решение, которое позволит мне нарисовать этого последнего персонажа, не перемещая курсор, но я не думаю, что это возможно.
Ответы
Ответ 1
error
должна быть такой же наблюдаемой, как бесконечный цикл. Вы можете только поймать error
в IO
, которая # l# Heading ## ike говорит "да, вы можете, если вы знаете магию". Но из действительно хорошей части 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
вокруг любого значения, которое может unsafeCleanup
к ошибке, чтобы превратить его в Maybe
.
Это доступно в пакете ложки, если вы не хотите писать его самостоятельно (и не должны - код исключения может быть очень сложным, особенно при наличии потоков).
Ответ 2
Вы можете сделать это, используя catch
от Control.Exception
. Обратите внимание, однако, что вы должны быть в монаде IO
, чтобы сделать это.
import qualified Control.Exception as Exc
divide :: Float -> Float -> Float
divide x 0 = error "Division by 0."
divide x y = x / y
main :: IO ()
main = Exc.catch (print $ divide 5 0) handler
where
handler :: Exc.ErrorCall -> IO ()
handler _ = putStrLn $ "You divided by 0!"