Как прочитать MonadReader и задать определение?

#haskell

#haskell

Вопрос:

Я пытаюсь выяснить, как прочитать следующее определение типа класса:

 Prelude Data.Functor.Identity Control.Monad.Reader> :i ask
class Monad m => MonadReader r (m :: * -> *) | m -> r where
  ask :: m r
  ...
  

m это тип более высокого уровня, и он должен быть monad .

Но что это m -> r означает?

Пытаюсь немного поиграть с ask следующим:

 Prelude Data.Functor.Identity Control.Monad.Reader> ask "Hello"
"Hello"
  

Почему я могу передать аргумент в ask ? Смотрим на сигнатуру типа:

 ask :: m r
  

Я не могу распознать, что я могу передать аргумент ask .

Комментарии:

1. Я думаю , идея заключается в том, что при попытке вызвать ask на String , вывод типа позволяет m быть унифицированным с функцией monad, так что в итоге вы получаете ask :: String -> String .

2. m -> r это функциональная зависимость; знания m достаточно, чтобы сделать вывод, что r это. По сути, это говорит о том, что вы не можете определить несколько MonadReader экземпляров для одной и той же монады, но с разными r именами.

3. У меня нет знаний, чтобы дать подробный ответ, но вкратце: m -> r это функциональная зависимость . А функции сами по себе являются экземпляром монады, так что это та монада, которую выбирает Haskell при выполнении ask "Hello" . (На самом деле, это просто сама монада Reader.)

Ответ №1:

m -> r Это функциональная зависимость, которая грубо указывает, что при попытке выбрать экземпляр MonadReader для использования, знания m достаточно для того, чтобы знать r . Другими словами, вы не можете определить два отдельных экземпляра с одинаковым, m но разным r значением.

Теперь, чтобы определить, какое определение ask использовать, мы переходим к выводу типа. Из его определения мы знаем, что он ask имеет тип MonadReader r m => m r . Из его использования в ask "Hello" мы знаем, что он также должен иметь тип like a -> b ; более конкретно, мы знаем, что он a объединяется с String , поскольку это тип "Hello" . Итак, наша задача — объединить MonadReader r m => m r с String -> b .

Это довольно просто. Переписывая String -> b в префиксной нотации и используя явные круглые скобки, мы можем объединить их вместе:

 MonadReader r m => m             r
                   ((->) String) b
  

Так m ~ ((->) String) и r ~ b (хотя мы все еще не знаем, что r/b должно быть). Просматривая доступные экземпляры MonadReader , мы находим (уникальный) экземпляр для m ~ (->) String (или, в более общем смысле, (->) r ):

 instance MonadReader r ((->) r) where
    ask       = id
    local f m = m . f
  

Итак, теперь мы знаем, что для нашего выбора m , ask = id . (Это также позволяет нам увидеть это r ~ b ~ String .)

И так, ask "Hello" == id "Hello" == "Hello" .

Обратите внимание, что ask не обязательно должно быть функцией. Это также может быть значением типа Reader r a , и в этом случае runReader необходимо использовать для извлечения функции.

 > :t runReader ask
runReader ask :: a -> a
> runReader ask "Hello"
"Hello"
  

Это также может быть более сложная монада, включающая ReaderT :

 > :t runReaderT ask
runReaderT ask :: Monad m => a -> m a
> runReaderT ask "Hello" :: Maybe String
Just "Hello"
> runReaderT ask "Hello" :: Either String String
Right "Hello"
  

Комментарии:

1. Я также не понимаю ask :: MonadReader r m => m r подпись типа. Почему подпись типа включает => ? Что это значит?

2. Это означает, что ask это значение типа m r для любой монады m и типа r , для которого существует MonadReader экземпляр.

3. Означает ли это, экземпляр monad типа r ?

4. Нет, r это тип, «обернутый» монадой m . По большей части экземпляры MonadReader являются (грубо говоря) либо функциями Reader (сами по себе просто оболочкой вокруг функции), либо монадами, созданными с использованием ReaderT . Это означает, что ask почти всегда есть значение, которое является функцией или из которого может быть извлечено.