如何理解" ap = liftM2 id"?的类型推断?

时间:2015-03-19 20:09:51

标签: haskell type-inference

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

ap     :: (Monad m) => m (a -> b) -> m a -> m b    
ap     =  liftM2 id

您是否可以帮助解释在ap应用于liftM2时如何推断id的类型?此外,问同等问题是否有效,但更具体地说,(a -> b -> c) -> m a在这种情况下如何减少到m (a -> b)

2 个答案:

答案 0 :(得分:6)

让我们试着找出liftM2 id的类型。首先,我们更改id中的类型参数,以便我们可以更轻松地解决这个问题。顺便说一下,id的类型为a -> a,而不是a -> b

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

接下来,我们在liftM2中添加其他括号,并记住a -> b -> c实际上是a -> (b -> c)

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

现在我们转移x -> y,以便它们与liftM2中的其他类型对齐:

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

确定。这告诉我们a ~ (b -> c)中的liftM2 id或:

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

现在我们可以使用这些专业版本:

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

我们删除了多余的括号,最后得到了正确的类型:

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

答案 1 :(得分:4)

id的类型为a -> a。第一个问题是我们如何统一 a -> a liftM2的论证类型(a -> b -> c)?诀窍是用a替换a -> a中的(a -> b)给我们(a -> b) -> (a -> b)或等同于(a -> b) -> a -> b。 (作为一个简洁的侧面说明,这是$的类型,这意味着$只是id的限制类型!)

现在我们将(a -> b) -> a -> bliftM2的整个类型结合起来:

Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r

我们将a1替换为a -> b,将a2替换为a,将r替换为b,然后向我们发送:

Monad m => ((a -> b) -> a -> b) -> m (a -> b) -> m a -> m b

最后,一旦我们将liftM2应用于id,结果将具有相同的类型减去第一个参数:

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

我们是:ap的类型。

对此的良好直觉是基于我之前关于$的观察。 $是正常的函数应用程序运算符; ap是函数应用程序解除了monad liftM2 ($)为您提供ap是有道理的,因为ap从根本上意味着...... id只是$的一个版本更通用的类型。