什么Haskell类型系统魔术允许连接的定义?

时间:2012-04-20 20:58:20

标签: haskell

join效用函数定义为:

join :: (Monad m) => m (m a) -> m a
join x = x >>= id

鉴于>>=的类型为Monad m => m a -> (a -> m b) -> m bida -> a,该函数如何也可以键入为a -> m b,因为它必须在上面的定义?在这种情况下,mb是什么?

2 个答案:

答案 0 :(得分:14)

a>>=类型中的id不一定是a个,所以让我们重新说明类型这样:

(>>=)    :: Monad m => m a     -> (a -> m b) -> m b
id       ::                        c -> c

因此,我们可以得出结论,c 毕竟a相同,至少当id>>=的第二个参数时......以及cm b相同。因此am b相同。换句话说:

(>>= id) :: Monad m => m (m b) ->               m b

答案 1 :(得分:10)

dave4420点击它,但我认为以下评论可能仍然有用。

您可以使用一些规则将某个类型有效地“重写”为与原始类型兼容的另一种类型。这些规则涉及用其他类型替换所有类型变量:

  • 如果您有id :: a -> a,则可以将a替换为c并获取id :: c -> c。后一种类型也可以重写为原始id :: a -> a,这意味着这两种类型是等价的。作为一般规则,如果将类型变量的所有实例替换为原始中无处不在的另一个类型变量,则会得到等效类型。
  • 您可以使用具体类型替换所有出现的类型变量。即,如果您有id :: a -> a,则可以将其重写为id :: Int -> Int。然而,后者无法重写为原始版本,因此在这种情况下,您专门化类型。
  • 比第二个规则更常见的是,您可以替换任何类型,具体或变量的所有类型变量。例如,如果您有f :: a -> m b,则可以将所有a替换为m b并获取f :: m b -> m b。由于这个也不能撤消,它也是一个专业化。

最后一个示例显示id如何用作>>=的第二个参数。所以你的问题的答案是我们可以重写和派生类型如下:

1. (>>=)    :: m a -> (a -> m b) -> m b        (premise)
2. id       :: a -> a                          (premise)
3. (>>=)    :: m (m b) -> (m b -> m b) -> m b  (replace a with m b in #1)
4. id       :: m b -> m b                      (replace a with m b in #2)
   .
   .
   .
n. (>>= id) :: m (m b) -> m b                  (indirectly from #3 and #4)