只是寻找解释以下作文的工作原理:
(=<<) . 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 - &gt; m b)匹配,即。如何将 return 的结果应用于(=&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; em&gt
答案 0 :(得分:7)
解释是:
return
(可能是意外)与您的=<<
不同的monad。(->) r
。编译器尝试将return :: c -> m' c
的结果与(a -> m b) -> m a -> m b
的第一个参数统一,因此unify m' c
与a -> m b
统一。唯一的可能性是m'
是某些(->) r
的读者monad r
。接下来,它尝试将(->) r c
与(转换为前缀表示法)(->) a (m b)
统一起来,通过将r
设置为a
并将c
设置为{{}来解决此问题。 1}}。因此,在统一之后,编译器将获得最通用的类型
m b
或以通常的中缀符号
return :: (m b) -> ((->) a (m b))
另见:
return :: (m b) -> (a -> m b)
实例的source。 修改:要定义monad,我们需要(部分应用)kind Monad ((->) r)
类型。这些几乎总是部分应用的数据构造函数,但在这种特殊情况下,我们将* -> *
视为一个类型运算符,它接受2个类型的参数并创建一个新类型(函数类型)。因此,对于任何给定类型->
,部分应用的表达式r
是一种类型(->) r
。事实证明,如何在其上描述monad操作有一种简单的方法。请参阅解释它的Control.Reader monad和this article。 * -> *
的monad操作的实现方式与Reader
完全相同,唯一的区别是(->)
将操作包装为不同的数据类型。
答案 1 :(得分:1)
我再次与涂鸦一起并排放置东西以帮助视觉理解:
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]