实现 Reader monad(来自 Real World Haskell 一书)
Implementing the Reader monad (from Real World Haskell book)
newtype Reader e a = R { runReader :: e -> a }
instance Monad (Reader e) where
return a = R $ \_ -> a
m >>= k = R $ \r -> runReader (k (runReader m r)) r
我很难理解这两个片段。我可以看出第一个是 reader 的记录语法描述,它具有从 e
到 a
的函数 runReader
,但第二个让我感到困惑。
通过将 m
与 k
绑定,它实际上是在尝试创建一个新的 Reader
,但是
runReader (k (runReader m r)) r
锻炼身体?我以为 runReader
只需要一个参数,但现在似乎需要两个参数,一个是 k (runReader m r)
另一个是 r
.
提前致谢。
I am having difficulty understanding the Reader Monad.
编辑:我应该指出一些关于这方面的资源,而不是试图重复它们。
- Monads for Functional Programming 作者:菲利普·瓦德勒。他称它们为 state reader monads.
- Chapter 22.1: Reader in HaskellBook.com 作者:Chris Allen 和 Julie Moronuki。
- Typeclassopedia: Monad Instances adapted from Brent Yorgey's The Monad.Reader issue 13.
- LYAH chapter 13: For a Few Monads More.
I thought runReader
only takes one argument, but it seems it's taking two right now, one being k (runReader m r)
and another being r
.
如果您查看 runReader :: Reader e a -> e -> a
的类型签名,这可以被视为采用 Reader e a
并生成 e -> a
,或者采用 Reader e a
和一个 e
并产生一个 a
。 reader monad 的要点是引入一个隐式参数。
How does runReader (k (runReader m r)) r
work out?
您可以详细说明 bind 运算符定义:
instance Monad (Reader e) where
return a = R $ \_ -> a
-- (>>=) :: Reader e a -> (a -> Reader e b) -> Reader e b
ma >>= k = R $ \e -> let a = runReader ma e
mb = k a
in runReader mb e
即首先“ma
是运行和e
”(runReader ma :: e -> a
应用于e
)。这会产生一个 a
.
那么k a
就是运行。这会产生一个 mb
.
那么“mb
是 运行 和 e
”(runReader mb :: e -> b
应用于 e
)。
这被打包成 R $ \e -> ... runReader mb e
。
我认为理解这一点的困难部分主要与 newtype 需要不断包装 (R
) 和展开 (runReader
) 的内容,而不是臭名昭著的 monads 的工作原理.
想象一下,您唯一需要的 monad 是 reader monad,我们可以不用 newtype
和 instance Monad (Reader e)
绒毛。那么您的定义可能如下所示:
type Reader e a = e -> a
-- type Reader e a = (->) e a
-- type Reader e = (->) e
unit :: a -> Reader e a
-- :: a -> (e -> a)
unit a = \_e -> a
-- unit a _e = a
-- unit = const
ask :: Reader e e
-- :: e -> e
ask = \e -> e
-- ask e = e
-- ask = id
bind :: Reader e a -> (a -> Reader e b) -> Reader e b
-- :: (e -> a) -> (a -> (e -> b)) -> (e -> b)
bind ma k = \e -> let a = ma e
mb = k a
in mb e
-- bind ma k e = let mb = k (ma e) in mb e
在这一点上变得更加清楚,所有 unit
所做的就是丢弃 e
,所有 ask
所做的就是 return e
,以及什么 bind
做的是采用两个函数(ma
和 k (ma e)
,又名 mb
),它们都需要一个 e
,将它们组合在一个新函数中,该函数也需要一个 e
,而不必在组合过程中显式传递 e
。
我在学习如何编写 monad 定义时有一个误解是 runReader
运行s 任何东西。它帮助我在概念上将其称为 unR
,因为它所做的只是删除 R
包装。
newtype Reader e a = R { runReader :: e -> a }
instance Monad (Reader e) where
return a = R $ \_ -> a
m >>= k = R $ \r -> runReader (k (runReader m r)) r
我很难理解这两个片段。我可以看出第一个是 reader 的记录语法描述,它具有从 e
到 a
的函数 runReader
,但第二个让我感到困惑。
通过将 m
与 k
绑定,它实际上是在尝试创建一个新的 Reader
,但是
runReader (k (runReader m r)) r
锻炼身体?我以为 runReader
只需要一个参数,但现在似乎需要两个参数,一个是 k (runReader m r)
另一个是 r
.
提前致谢。
I am having difficulty understanding the Reader Monad.
编辑:我应该指出一些关于这方面的资源,而不是试图重复它们。
- Monads for Functional Programming 作者:菲利普·瓦德勒。他称它们为 state reader monads.
- Chapter 22.1: Reader in HaskellBook.com 作者:Chris Allen 和 Julie Moronuki。
- Typeclassopedia: Monad Instances adapted from Brent Yorgey's The Monad.Reader issue 13.
- LYAH chapter 13: For a Few Monads More.
I thought
runReader
only takes one argument, but it seems it's taking two right now, one beingk (runReader m r)
and another beingr
.
如果您查看 runReader :: Reader e a -> e -> a
的类型签名,这可以被视为采用 Reader e a
并生成 e -> a
,或者采用 Reader e a
和一个 e
并产生一个 a
。 reader monad 的要点是引入一个隐式参数。
How does
runReader (k (runReader m r)) r
work out?
您可以详细说明 bind 运算符定义:
instance Monad (Reader e) where
return a = R $ \_ -> a
-- (>>=) :: Reader e a -> (a -> Reader e b) -> Reader e b
ma >>= k = R $ \e -> let a = runReader ma e
mb = k a
in runReader mb e
即首先“ma
是运行和e
”(runReader ma :: e -> a
应用于e
)。这会产生一个 a
.
那么k a
就是运行。这会产生一个 mb
.
那么“mb
是 运行 和 e
”(runReader mb :: e -> b
应用于 e
)。
这被打包成 R $ \e -> ... runReader mb e
。
我认为理解这一点的困难部分主要与 newtype 需要不断包装 (R
) 和展开 (runReader
) 的内容,而不是臭名昭著的 monads 的工作原理.
想象一下,您唯一需要的 monad 是 reader monad,我们可以不用 newtype
和 instance Monad (Reader e)
绒毛。那么您的定义可能如下所示:
type Reader e a = e -> a
-- type Reader e a = (->) e a
-- type Reader e = (->) e
unit :: a -> Reader e a
-- :: a -> (e -> a)
unit a = \_e -> a
-- unit a _e = a
-- unit = const
ask :: Reader e e
-- :: e -> e
ask = \e -> e
-- ask e = e
-- ask = id
bind :: Reader e a -> (a -> Reader e b) -> Reader e b
-- :: (e -> a) -> (a -> (e -> b)) -> (e -> b)
bind ma k = \e -> let a = ma e
mb = k a
in mb e
-- bind ma k e = let mb = k (ma e) in mb e
在这一点上变得更加清楚,所有 unit
所做的就是丢弃 e
,所有 ask
所做的就是 return e
,以及什么 bind
做的是采用两个函数(ma
和 k (ma e)
,又名 mb
),它们都需要一个 e
,将它们组合在一个新函数中,该函数也需要一个 e
,而不必在组合过程中显式传递 e
。
我在学习如何编写 monad 定义时有一个误解是 runReader
运行s 任何东西。它帮助我在概念上将其称为 unR
,因为它所做的只是删除 R
包装。