我被困在 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)) …
的实例声明中的实例声明的父类(super class)中没有 ‘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 -> ???
但我坚持使用
???
部分。书中给出了以下提示:
We got the definition of the apply function started for you, we’ll describe what you need to do and you write the code. If you unpack the type of Reader’s apply above, you get the following.
<*> :: (r -> a -> b) -> (r -> a) -> (r -> b) -- contrast this with the type of fmap fmap :: (a -> b) -> (r -> a) -> (r -> b)
So what’s the difference? The difference is that
apply
, unlikefmap
, also takes an argument of typer
.Make it so.
是的,但如何做到这一点?使用类型化的孔,编译器告诉我
???
的类型必须是 b
.但是我仍然看不到如何构造一个接受 r
的 lambda 表达式。并返回 b
类型的内容, 给定 rab
和 ra
.
最佳答案
让我们打网球吧。看着你范围内的作品,
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
)。
关于haskell - 为 Reader r 编写 Applicative 实例时如何编写 <*>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40060162/