Пользовательское может охранять механизм быть определенным в Haskell?

Если Вы смотрите на пример для catches:

 f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex),
                     Handler (\ (ex :: IOException)    -> handleIO    ex)]

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

Править: К вашему сведению ниже источник GHC для выгод. Если бы кто-то может пролить некоторый свет на то, как это работает, это было бы большим.

catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catch` catchesHandler handlers

catchesHandler :: [Handler a] -> SomeException -> IO a
catchesHandler handlers e = foldr tryHandler (throw e) handlers
    where tryHandler (Handler handler) res
              = case fromException e of
                Just e' -> handler e'
                Nothing -> res
6
задан me2 16 February 2010 в 16:40
поделиться

2 ответа

Это Scoped Type Variables расширение GHC в действии. Перейдите по ссылке, чтобы узнать больше.

По сути, вы определяете утверждение о типе, которому должен соответствовать шаблон, прежде чем он сможет соответствовать. Так что да, это похоже на охрану, но не совсем так.

Как работает этот конкретный пример? Погрузитесь в источники «базовой» библиотеки , чтобы узнать, что:

class (Show e) => Exception e where
    toException   :: e -> SomeException
    fromException :: SomeException -> Maybe e

data SomeException = forall e . Exception e => SomeException e

instance Exception IOException where
    toException = IOException
    fromException (IOException e) = Just e
    fromException _ = Nothing

instance Exception ArithException where
    toException = ArithException
    fromException (ArithException e) = Just e
    fromException _ = Nothing

Мы видим, что IOException и ArithException являются разными типами, реализующими исключение класса типов Exception . Мы также видим, что toException / fromException - это механизм упаковки / развертывания, который позволяет преобразовывать значения типа Exception в / из значений типов IOException , ] ArithException и т. Д.

Итак, мы могли бы написать:

f = expr `catches` [Handler handleArith,
                    Handler handleIO]

handleArith :: ArithException -> IO ()
handleArith ex = ....

handleIO :: IOException -> IO ()
handleIO ex = ....

Предположим, что происходит IOException . Когда catchesHandler обрабатывает первый элемент списка обработчиков, он вызывает tryHandler , который вызывает fromException . Из определения tryHandler следует, что тип возвращаемого значения fromException должен быть таким же, как аргумент handleArith . С другой стороны, e имеет тип Exception, а именно - (IOException ...).Итак, типы разыгрываются следующим образом (это недействительный haskell, но я надеюсь, что вы уловили мою точку зрения):

fromException :: (IOException ...) -> Maybe ArithException

Из экземпляра Exception IOException ... сразу следует, что результатом является Ничего , поэтому этот обработчик пропускается. По той же причине будет вызван следующий обработчик, потому что fromException вернет (Just (IOException ...)) .

Итак, вы использовали сигнатуры типов handleArith и handleIO , чтобы указать, когда каждый из них будет вызван, а fromException / toException убедился, что это случилось так.

Если хотите, вы также можете ограничить типы handleIO и handleArith внутри определения f , используя переменные типа с ограниченной областью видимости. Возможно, это может улучшить читаемость.

Завершение, переменные типа с ограниченным типом здесь не являются основными игроками. Они просто используются для удобства. Основным механизмом для разыгрывания таких трюков является fromException / toException и другие. Переменные типа с ограниченной областью видимости просто позволяют вам иметь синтаксис, который больше напоминает защитные шаблоны.

5
ответ дан 17 December 2019 в 02:28
поделиться
case () of 
  ()| foo expr1 -> handleFooCase
    | bar expr2 -> handleBarCase
    | otherwise -> blah
1
ответ дан 17 December 2019 в 02:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: