函数组合提示

7

我想解释一下以下组合是如何工作的:

(=<<) . return

where

(=<<) ::       (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的结果应用于期望函数类型的(=<<)的第一个参数?


1
(=<<) . return :: (Monad ((->) a), Monad m) => m b -> m a -> m b 是一个更完整的类型签名,它明确地显示了函数实例。 - Sarah
谢谢。不幸的是,这个额外的限制并没有为更好的理解提供任何线索。让Int返回并且Monad m是Maybe类型,所以结果是Maybe Int。如果应用于(=<<),我会得到一个错误*GHCi>:t (=<<) (Just 1)无法匹配期望的类型a0 -> m0 b0'与实际类型Maybe a1'*。 - David Unric
到目前为止,我们已经看到return在这里是const的同义词。它的意义由其属于((->) a)单子确定。(=<<) . return === flip (>>)。因此,你上面评论中Just1的使用都是错误的。必须使用const代替Just,并且必须使用一些单子值代替1,例如(=<<) (const [1]) "xyz"会产生[1,1,1] - Will Ness
好的,我已经知道了。在阅读Pudlak的回答后,我明白了。 - David Unric
@DavidUnric 太好了! :) 我只是想明确地把它“写下来”。 - Will Ness
2个回答

7

解释如下:

  1. return的返回值与=<<使用的单子不同,可能会有意外情况。
  2. 它使用的单子是读取器单子 (->) r

编译器试图将return :: c -> m' c的结果与(a -> m b) -> m a -> m b 的第一个参数统一起来,所以要将m' ca -> m b 统一。唯一的可能性是m'是某个r的读取器单子(->) r。接下来,它尝试将(->) r c与(转换为前缀表示法)(->) a (m b) 统一,这通过将r设置为ac设置为m b来解决。因此,在统一后,编译器得到了最通用的类型。

return :: (m b) -> ((->) a (m b))

或者使用通常的中缀表示法。
return :: (m b) -> (a -> m b)

另请参阅:


编辑:要定义一个Monad,我们需要一个类型的(部分应用) kind* -> *。这些几乎总是部分应用的数据构造函数,但在这种特殊情况下,我们将->视为一个类型运算符,它接受2个类型参数并创建一个新类型(函数类型)。因此,对于任何给定的类型r,部分应用的表达式(->) r是一种* -> *类型。事实证明,有一种简单的方法来描述它上面的monad操作。请参见Control.Reader monad以及这篇文章,它解释了这一点。对于Reader的monad操作与(->)完全相同,唯一的区别是Reader将操作封装到一个不同的数据类型中。


谢谢。我只是没有意识到读取器单子必须应用于实现类型统一。因此,剩下的问题是区分函数类型、类型构造函数和“读取器单子”。我猜测读取器单子是类型构造函数的特殊情况,而函数类型等同于类型构造函数,但我可能错了。 - David Unric
1
@DavidUnric:嗯,函数箭头(->)实际上是一种类型构造器(属于* -> * -> *的种类)。当然,你可以部分应用它到某个类型r上,并得到(->) r :: * -> *,这与m完全匹配。Reader Monad不过是对这个部分应用的函数箭头的一个Monad实例而已。 - Vitus

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]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接