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

Неопределенная ошибка переменной типа msg

Я не думаю, что это ошибка, но я немного озадачен тем, почему это не работает. Бонусный вопрос - почему он упоминает переменную e? Нет переменной e.

    Prelude> :m +Control.Exception
    Prelude Control.Exception> handle (\_-> return "err") undefined

    <interactive>:1:0:
        Ambiguous type variable `e' in the constraint:
          `Exception e'
            arising from a use of `handle' at <interactive>:1:0-35
        Probable fix: add a type signature that fixes these type variable(s)
    Prelude Control.Exception> 

По-видимому, он отлично работает в ghci 6.8, я использую 6.10.1.

Изменить: я минимизировал код. Я ожидаю, что тот же результат и в 6,8 и 6,10

class C a                                                                                                     

foo :: C a => (a -> Int)-> Int                                                                                
foo _ = 1                                                                                                     

arg :: C a => a -> Int                                                                                        
arg _ = 2                                                                                                     

bar :: Int                                                                                                    
bar = foo arg

пытается скомпилировать его:

[1 of 1] Compiling Main             ( /tmp/foo.hs, interpreted )

/tmp/foo.hs:12:10:
    Ambiguous type variable `a' in the constraint:
      `C a' arising from a use of `arg' at /tmp/foo.hs:12:10-12
    Probable fix: add a type signature that fixes these type variable(s)
Failed, modules loaded: none.
Prelude Control.Exception> 
4b9b3361

Ответ 1

Тип Control.Exception.handle:

handle :: Exception e => (e -> IO a) -> IO a -> IO a

Проблема, которую вы видите, заключается в том, что выражение лямбда (\_ -> return "err") не относится к типу e -> IO a, где e является экземпляром Exception. Ясно, как грязь? Хорошо. Теперь я предоставлю решение, которое должно быть полезно:)

В вашем случае так бывает, что e должен быть Control.Exception.ErrorCall, так как undefined использует error, который выдает ErrorCall (экземпляр Exception).

Чтобы обрабатывать использование undefined, вы можете определить что-то вроде handleError:

handleError :: (ErrorCall -> IO a) -> IO a -> IO a
handleError = handle

Он по существу является псевдонимом Control.Exception.handle с e исправленным как ErrorCall, который представляет собой error.

Похоже на это при запуске в GHCi 7.4.1:

ghci> handleError (\_ -> return "err") undefined
"err"

Для обработки всех исключений функция handleAll может быть записана следующим образом:

handleAll :: (SomeException -> IO a) -> IO a -> IO a
handleAll = handle

Учет всех исключений имеет последствия, хорошо описанные в этой выдержке документации Control.Exception:

Захват всех исключений

Можно исключить все исключения, используя тип SomeException:

catch f (\e -> ... (e :: SomeException) ...)

ОДНАКО, это обычно не то, что вы хотите сделать!

Например, предположим, что вы хотите прочитать файл, но если он не существует, продолжайте, как если бы он содержал "". У вас может возникнуть соблазн просто перехватить все исключения и вернуть "" в обработчик. Однако это имеет всевозможные нежелательные последствия. Например, если пользователь нажимает на control-C только в нужный момент, тогда будет исключено исключение UserInterrupt, и программа продолжит работу, полагая, что файл содержит "". Аналогично, если другой поток пытается убить поток, читающий файл, тогда исключение ThreadKilled будет проигнорировано.

Вместо этого вы должны только поймать именно те исключения, которые вы действительно хотите. В этом случае это, скорее всего, будет более конкретным, чем даже "любое исключение IO"; ошибка разрешений, вероятно, также будет обрабатываться по-разному. Вместо этого вы, вероятно, захотите что-то вроде:

 e <- tryJust (guard . isDoesNotExistError) (readFile f)
 let str = either (const "") id e

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

Но иногда вам действительно нужно улавливать какое-либо исключение и фактически видеть, что такое исключение. Один пример - на самом верхнем уровне программы, вы можете захотеть поймать любое исключение, распечатать его в файле журнала или на экране, а затем выйти изящно. Для этих случаев вы можете использовать catch (или одну из других исключающих функций) с типом SomeException.

Источник: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html#g:4

Ответ 2

Эта проблема проявляется только в GHC 6.10; он не может быть дублирован в GHC 6.8, потому что тип handle отличается:

: [email protected] 620 ; ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
Loading package base ... linking ... done.
Prelude> :m +Control.Exception
Prelude Control.Exception>  handle (\_ -> return "err") undefined
"err"
Prelude Control.Exception> 

ОК, возможно, я смогу получить это право наконец. Я думаю, проблема заключается не в ограничении мономорфизма, а в том, что вы попали в экземпляр проблемы Read/Show: вы предлагаете обработать некоторый тип исключения, в новой версии `handle, существует более одного типа исключения, и тип этого исключения не отображается в вашем результате. Поэтому компилятор не знает, какой тип исключения вы пытаетесь обработать. Один из способов этого - выбрать. Вот какой код работает:

Prelude Control.Exception> let alwaysError :: SomeException -> IO String; alwaysError = \_ -> return "err"
Prelude Control.Exception> handle alwaysError undefined
"err"

Кстати, пример использования handle в документации библиотеки GHC не компилируется под 6.10. Я опубликовал отчет об ошибке.

Ответ 3

Обходным путем является использование Control.OldException в ghc 6.10. * вместо Control.Exception.

Ответ 4

Попробуйте дать вашему обработчику тип SomeException -> IO x, где x - конкретный тип, например

import Control.Exception
let f _ = putStrLn "error" :: SomeException -> IO () 
in handle f undefined 

Ответ 5

"Исключение e", скорее всего, из сигнатуры типа "handle".

Документация говорит:

handle :: Exception e => (e -> IO a) -> IO a -> IO a

В GHC 6.8 он был другим, что объясняет, почему я не получаю эту ошибку.

handle :: (Exception -> IO a) -> IO a -> IO a

Кажется, вы сталкиваетесь с ограничением мономорфизма. Это "_" - шаблон должен быть мономорфным (что он есть с ghc 6.8) или явно напечатан. "Обходной путь" заключается в том, чтобы поместить шаблон в левую часть определения, где он представляет собой "простую привязку шаблона", как указано в отчете Haskell.

Попробуйте следующее:

let f _ = return "err"
handle f undefined

http://www.haskell.org/haskellwiki/Monomorphism_restriction