只是在寻找以下组合如何工作的解释:
(=<<) . return
哪里
(=<<) :: (a -> m b) -> m a -> m b
return :: a -> m a
(.) :: (b -> c) -> (a -> b) -> a -> c
最终类型:
GHCi> :t (=<<) . return
(=<<) . return :: Monad m => m b -> m a -> m b
我无法理解如何将 m a 与 (a -> m b( 匹配,即如何将简单类型的返回结果应用于期望函数类型的 (=<<( 的第一个参数?
解释是:
- 您的
return
(也许出乎意料地(与您的=<<
不同
。 - 它使用的单子是阅读器单子
(->) r
。
编译器试图将return :: c -> m' c
的结果与(a -> m b) -> m a -> m b
的第一个参数统一起来,以便将m' c
与a -> m b
统一。唯一的可能性是m'
是读者monad (->) r
某些r
。接下来,它尝试将(->) r c
与(转换为前缀表示法(统一 (->) a (m b)
,这是通过将r
设置为 a
并将 c
设置为 m b
来解决的。因此,在统一之后,编译器将获得最通用的类型
return :: (m b) -> ((->) a (m b))
或通常的中缀表示法
return :: (m b) -> (a -> m b)
另请参阅:
- 如何使用 (->( Monad 实例和对 (->( 的混淆
- 定义
Monad ((->) r)
实例的源。
编辑:要定义一个monad,我们需要一个(部分应用的(类型的* -> *
。这些几乎总是部分应用的数据构造函数,但这种特殊情况,我们将->
视为一个类型运算符,它接受 2 个类型参数并创建一个新类型(函数类型(。所以对于任何给定的r
类型,部分应用的表达式(->) r
是一种类型* -> *
。事实证明,有一种直接的方法可以描述对它的 monad 操作。请参阅 Control.Reader monad 以及解释它的文章。Reader
的 monad 运算的实现方式与 (->)
完全相同,唯一的区别是Reader
将运算包装成不同的数据类型。
我再次,涂鸦,将东西并排放置以帮助视觉理解:
g = ((=<<) . return) {-
((=<<) . return) x y
=== (=<<) (return x) y return :: a' -> m' a'
(=<<) :: (a -> m b) -> m a -> m b return x :: m' a' , x :: a'
m' a' m' ~ ((->) a) , a' ~ m b
return x === const x -- instance Monad ((->) a) where return = const
g x y === y >>= (_ -> x) === y >> x (!!)
-}
g :: m b -> m a -> m b
所以事实证明(也许从类型签名中可以明显看出(, g === flip (>>)
:
Prelude> ((=<<).return) [1] "xyz" -- === (=<<) (const [1]) "xyz"
-- === "xyz" >>= const [1]
-- === "xyz" >> [1]
-- === (>> [1]) "xyz"
[1,1,1]