haskell - 为 Reader r 编写 Applicative 实例时如何编写 <*>

标签 haskell applicative

我被困在 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, unlike fmap, also takes an argument of type r.

Make it so.



是的,但如何做到这一点?使用类型化的孔,编译器告诉我 ??? 的类型必须是 b .但是我仍然看不到如何构造一个接受 r 的 lambda 表达式。并返回 b 类型的内容, 给定 rabra .

最佳答案

让我们打网球吧。看着你范围内的作品,

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)

请注意 rabra都收到r作为论据。组合 Reader 中的所有步骤计算可以访问相同的环境。

顺便说一句,这个定义使得 <*>相当于著名的 S combinator (和 pureK )。

关于haskell - 为 Reader r 编写 Applicative 实例时如何编写 <*>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40060162/

相关文章:

haskell - 如何实现这种 Traversable 使用模式?

haskell - 将 `Functor` 类泛化为 `MultiFunctor`?

haskell - lambda 表达式中的应用仿函数、非穷举模式?

haskell - 如何判断一个 monad 是否可交换?

Haskell 合并多个列表

list - 如何在没有 GADT 或数据类型上下文的情况下定义 List 的 Eq 实例

haskell - 对纯应用程序的需求

haskell - 管道和创建基于管道的库

haskell - 如何在 Haskell 中迭代具有内存限制的树?

haskell - 为什么静态箭头概括了箭头?