Как написать при написании прикладного экземпляра для Reader r

#haskell #applicative

#haskell #прикладной

Вопрос:

Я застрял в упражнении из книги Хаскелла «Глава 22. Читатель». В упражнении говорится «Реализовать приложение для Reader», и оно дает следующее:

 {-# LANGUAGE InstanceSigs #-}

newtype Reader r a =
  Reader { runReader :: r -> a }

instance Applicative (Reader r) where 
  pure :: a -> Reader r a
  pure a = Reader $ ???

  (<*>) :: Reader r (a -> b) -> Reader r a -> Reader r b
  (Reader rab) <*> (Reader ra) = Reader $ r -> ???
 

Я смог написать pure после того, как также написал Functor экземпляр (я написал Functor экземпляр, потому что в противном случае GHC жаловался «Нет экземпляра для (Functor (Reader r)) … возникновения из суперклассов объявления экземпляра в объявлении экземпляра для ‘Applicative (Reader r)’ «):

 {-# LANGUAGE InstanceSigs #-}

newtype Reader r a =
  Reader { runReader :: r -> a }

instance Functor (Reader r) where
  fmap f (Reader x) = Reader (f . x)

instance Applicative (Reader r) where
  pure :: a -> Reader r a
  pure a = Reader $ _ -> a

  (<*>) :: Reader r (a -> b) -> Reader r a -> Reader r b
  (Reader rab) <*> (Reader ra) = Reader $ r -> ???
 

Но я застрял с этой ??? частью.

В книге дается следующий совет:

Мы запустили для вас определение функции apply, мы опишем, что вам нужно сделать, и вы напишете код. Если вы распакуете тип приложения для чтения, указанный выше, вы получите следующее.

 <*> :: (r -> a -> b) 
    -> (r -> a) 
    -> (r -> b)

 -- contrast this with the type of fmap

fmap :: (a -> b) 
     -> (r -> a)
     -> (r -> b)
 

Так в чем разница? Разница в том, что apply , в отличие
fmap от , также принимает аргумент типа r .

Сделайте это так.

Да, но как это сделать? Используя типизированные отверстия, компилятор сообщает мне, что тип ??? должен быть b . Но я все еще не вижу, как я могу построить лямбда-выражение, которое принимает r и возвращает что-то типа b , учитывая rab и ra .

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

1. Можете ли вы также предоставить определение типа Reader данных для тех из нас, кто не собирается покупать эту книгу?

2. @Rhymoid Это немного жестко. Reader В конце концов, то, что есть, общеизвестно.

3. Извините за отсутствующий тип Reader, я добавил его в вопрос выше.

Ответ №1:

Давайте поиграем в теннис типов. Посмотрите на фрагменты, которые у вас есть в области видимости,

 rab :: r -> (a -> b)
ra :: r -> a
r :: r
 

и тип цели b , вы можете видеть, что единственный способ получить b выход — это применить rab к двум аргументам.

 Reader rab <*> Reader ra = Reader $ r -> rab _ _
 

Теперь у первого отверстия есть тип r , и у вас есть только один r в области видимости.

 Reader rab <*> Reader ra = Reader $ r -> rab r _
 

Оставшееся отверстие имеет тип a . Единственное a , что у вас есть в области видимости, это возвращаемое значение ra ,

 Reader rab <*> Reader ra = Reader $ r -> rab r (ra _)
 

и ra аргумент ‘s должен быть an r , для которого у вас снова есть только один выбор.

 Reader rab <*> Reader ra = Reader $ r -> rab r (ra r)
 

Обратите внимание на это rab , и ra оба получают r в качестве аргумента. Все этапы составного Reader вычисления имеют доступ к одной и той же среде.

Кстати, это определение <*> эквивалентно знаменитому S combinator pure есть K ).