Как записать все исключения в Haskell? - PullRequest
0 голосов
/ 18 февраля 2019

Оригинальный заголовок : Как работать с несколькими экземплярами типов исключений при проверке всех исключений?

У меня есть следующие импорта (обратите внимание, что моя прелюдия на самом деле ClassyPrelude, который использует UnliftIO.Exception ).Обратите внимание, что System.Logger из tinylog , тонкой библиотеки поверх fast-logger .

import           Prelude                   hiding(log)
import           System.Logger             hiding(log)
import qualified System.Logger             as TL

И следующей функции:

logExceptions :: MonadUnliftIO m => Logger -> m a -> m a
logExceptions logger program = withException program
  (\ex -> do
    logIt Warn logger ["Logging exception: ", (show ex)]
    flush logger
    )

Помещение лямбды в локальную функцию с типом может сделать ее немного более понятной:

logExceptions :: MonadUnliftIO m => Logger -> m a -> m a
logExceptions logger program = withException program logEx
  where
    logEx :: (MonadUnliftIO m, Exception e) => e -> m ()
    logEx ex = do
      logIt Warn logger ["Logging exception: ", (show ex)]
      flush logger

Это приводит к следующей ошибке компиляции:

    * Could not deduce (Exception e0)
        arising from a use of `withException'
      from the context: MonadUnliftIO m
        bound by the type signature for:
                   logExceptions :: forall (m :: * -> *) a.
                                    MonadUnliftIO m =>
                                    Logger -> m a -> m a
        at src/FDS/Logging.hs:19:1-56
      The type variable `e0' is ambiguous
      These potential instances exist:
        instance Exception SomeException -- Defined in `GHC.Exception.Type'
        instance Exception IOException -- Defined in `GHC.IO.Exception'
        instance Exception SomeAsyncException
          -- Defined in `GHC.IO.Exception'
        ...plus four others         
        ...plus 30 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    * In the expression: withException program logEx
      In an equation for `logExceptions':
          logExceptions logger program
            = withException program logEx
            where                   
                logEx :: (MonadUnliftIO m, Exception e) => e -> m ()
                logEx ex            
                  = do logIt Warn logger ...
                       ....         
   |                                
20 | logExceptions logger program = withException program logEx
   |         

Наиболее тревожныйбит это plus 30 instances involving out-of-scope types.Я мог бы скрыть этот импорт, чтобы немного улучшить ситуацию:

import           GHC.Exception.Type        hiding(SomeException)
import           GHC.IO.Exception          hiding(IOException, SomeAsyncException)

Но вряд ли разумно пройтись и найти все 30+ типов исключений и замаскировать их все таким образом.Я предполагаю, что я делаю что-то совершенно не так, или мне действительно нужно пройти через все и замаскировать все?

Примечание :

  1. Мой logItфункция - это всего лишь тонкая оболочка для функции log из tinylog - не стесняйтесь заменить ее на то, что кажется эргономичным.

1 Ответ

0 голосов
/ 19 февраля 2019

Теперь я понимаю, что моя проблема заключалась в том, что для аргумента Exception требовался конкретный тип, поскольку это полиморфная функция, как указано в моем вопросе, и нет сайта вызова, который бы сузил это до определенного типа.Правильный ответ описан в Catch 'em all! здесь , и он должен использовать конкретный тип SomeException.Полученный код:

logExceptions :: MonadUnliftIO m => Logger -> m a -> m a
logExceptions logger program = withException program logEx
  where
    logEx :: MonadUnliftIO m => SomeException -> m ()
    logEx ex = do
      logIt Warn logger ["Logging exception: ", (show ex)]
      flush logger
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...