Подтвердить что ты не робот

Как поймать (и игнорировать) вызов функции ошибки?

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

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

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

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

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

4b9b3361

Ответ 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!"