函数组成提示



只是在寻找以下组合如何工作的解释:

(=<<) . 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( 匹配,即如何将简单类型的返回结果应用于期望函数类型的 (=<<( 的第一个参数?

解释是:

  1. 您的return(也许出乎意料地(与您的=<<不同
  2. 它使用的单子是阅读器单子(->) r

编译器试图将return :: c -> m' c的结果与(a -> m b) -> m a -> m b的第一个参数统一起来,以便将m' ca -> 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]

相关内容

  • 没有找到相关文章

最新更新