我在Haskell Book,“第22章读者”中练习。练习说“实施读者的应用”,它给出了以下内容:
{-# 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
的lambda表达式,并返回类型为b
的东西,给定rab
和ra
。
答案 0 :(得分:11)
让我们打网球。看看你在范围内的作品,
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
的参数必须是r
,再次只有一个选择。
Reader rab <*> Reader ra = Reader $ \r -> rab r (ra r)
请注意rab
和ra
都接收r
作为参数。组合Reader
计算中的所有步骤都可以访问相同的环境。
顺便提一下,此定义使<*>
等同于着名的S
combinator(pure
为K
)。