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

Emr*_*inç 8 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 -> ???
Run Code Online (Sandbox Code Playgroud)

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 -> ???
Run Code Online (Sandbox Code Playgroud)

但我坚持这???部分.

该书给出了以下提示:

我们为您启动了apply函数的定义,我们将描述您需要做什么并编写代码.如果您打开上面适用的Reader类型,您将获得以下内容.

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

 -- contrast this with the type of fmap

fmap :: (a -> b) 
     -> (r -> a)
     -> (r -> b)
Run Code Online (Sandbox Code Playgroud)

那有什么区别?不同之处在于apply,它 fmap也采用了类型的论证r.

这样做.

是的,但如何做到这一点?使用类型化的孔,编译器告诉我???必须是类型b.但我仍然无法看到如何构造一个lambda表达式,它接受一个r类型b,给定rab和返回的东西ra.

Ben*_*son 11

看看你在范围内的作品,

rab :: r -> (a -> b)
ra :: r -> a
r :: r
Run Code Online (Sandbox Code Playgroud)

和你的目标类型b,你可以看到你可以b通过应用rab两个参数的唯一方法.

Reader rab <*> Reader ra = Reader $ \r -> rab _ _
Run Code Online (Sandbox Code Playgroud)

现在,第一个洞有一个类型r,你只有一个r在范围内.

Reader rab <*> Reader ra = Reader $ \r -> rab r _
Run Code Online (Sandbox Code Playgroud)

剩下的洞有一种类型a.a你在范围内唯一的是返回值ra,

Reader rab <*> Reader ra = Reader $ \r -> rab r (ra _)
Run Code Online (Sandbox Code Playgroud)

而且ra这个论点必须是一个r,你再一次只有一个选择.

Reader rab <*> Reader ra = Reader $ \r -> rab r (ra r)
Run Code Online (Sandbox Code Playgroud)

请注意,rab并且rar作为参数接收.组合Reader计算中的所有步骤都可以访问相同的环境.

顺便提一下,这个定义<*>相当于着名的S组合子(并且pureK).