2012-04-20 49 views
5

join效用函数被定义为:Haskell类型系统魔法允许定义连接吗?

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是什么?

+9

会发生什么,如果'了'是'M B',如'id'迫使它呢?这应该回答你的问题。 – 2012-04-20 21:01:23

+0

这种魔法的味道通常被称为“统一”:) – 2012-04-21 16:18:12

回答

13

a S IN的类型>>=id不一定相同a S,让我们重申类型是这样的:

(>>=) :: 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 
10

dave4420撞击它,但我认为以下几点意见可能仍然是有用的。

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

  • 如果你有id :: a -> a,你可以用c替代a并获得id :: c -> c。后一种类型也可以重写为原始的id :: a -> a,这意味着这两种类型是等价的。作为一般规则,如果将所有类型变量的实例替换为原来无处不在的另一个类型变量,则会得到一个等效类型。
  • 您可以用具体类型替换所有出现的类型变量。即,如果您有id :: a -> a,则可以将其重写为id :: Int -> Int。但后者不能改写回原来的,所以在这种情况下,你是专门为的类型。
  • 比第二条规则更一般,您可以替换所有类型变量的任何类型,具体或变量。例如,如果您有f :: a -> m b,则可以用m b替换所有出现的a,并获得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)