Многопараметрические контекстные ограничения в haskell - PullRequest
0 голосов
/ 10 ноября 2018

Я сейчас читаю газету Монадные трансформаторы Шаг за шагом Мартин Грабмюллер.

В статье есть часть, где он перечисляет следующую декларацию экземпляра:

instance (MonadError e m) => MonadError e (ReaderT r m) where...

Я просмотрел все, но не могу найти какой-либо информации о том, что именно означает многопараметрическое ограничение, например (Foo a b). Я не совсем понимаю, как e и m работают вместе в головке экземпляра => MonadError e (ReaderT r m).

Как работают эти многопараметрические ограничения? Спасибо!

1 Ответ

0 голосов
/ 10 ноября 2018

По существу, ограничение типа Show a ограничивает переменную типа a для представления отображаемого типа. Вы, кажется, понимаете это.

Ограничение вида C a b ограничивает пару переменных типа a и b. Интуитивно, это ограничение означает, что между такими типами существует связь.

Рассмотрим этот вымышленный класс

class C a b where
   sum :: a -> b -> (Int, b)

Интуитивно понятно, что ограничение C a b означает, что a и b могут быть sum med вместе (в таком порядке!), И результатом этой суммы будет пара (Int, b).

В вашем случае вы имеете дело с

class Monad m => MonadError e m | m -> e where
   throwError :: e -> m a

Здесь MonadError e m выражает следующее соотношение между e и m.

  1. m - это монада
  2. e - это тип, для которого мы можем преобразовать любое значение x :: e в throwError x :: m a для любого a. Интуитивно понятно, что это тип «ошибка», представляющий природу некоторой ошибки, и throwError просто включает такое значение внутри монады
  3. учитывая m, есть только один тип ошибки e. Другими словами, отношение на самом деле является функцией. Это выражается через функциональную зависимость ... | m -> e в вышеприведенном классе.

Простая версия: MonadError m a означает, что m является монадой, которая может выражать некоторые "значения ошибок", типа e.

Например, если у нас есть MonadError M String в наличии, мы можем написать

foo :: Int -> M Int
foo n | n == 0    = throwError "can't handle zero!"
      | otherwise = return (100 `div` n)
...