#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
).