[英]Why does haskell's bind function take a function from non-monadic to monadic
[英]Haskell: why does 'id' make this function no longer monadic?
我试图理解为什么在下面的序列的最后一行添加id
会删除monadic方面:
Prelude> :t id
id :: a -> a
Prelude> :t Control.Monad.liftM2
Control.Monad.liftM2
:: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
Prelude> :t (==)
(==) :: Eq a => a -> a -> Bool
Prelude> :t Control.Monad.liftM2 (==)
Control.Monad.liftM2 (==)
:: (Monad m, Eq a) => m a -> m a -> m Bool
Prelude> :t Control.Monad.liftM2 (==) id
Control.Monad.liftM2 (==) id :: Eq a => (a -> a) -> a -> Bool
Prelude>
如何添加id :: a -> a
以最后一行的方式更改签名?
您正在将类型修改为特定的Monad
实例,即“函数阅读器”monad( instance Monad ((->) a)
)。
id :: a -> a
并且您尝试将其用作ma
类型参数的参数,因此:
m a ~ a -> a
m a ~ (->) a a
m a ~ ((->) a) a
m ~ (->) a
a ~ a
签名的其余部分是:
m a -> m Bool
由于m ~ (->) a
,结果类型为:
(->) a a -> (->) a Bool
(a -> a) -> (a -> Bool)
(a -> a) -> a -> Bool
(加上Eq a
使用==
Eq a
约束。)
这在pointfree代码中很有用,特别是使用Applicative
实例,因为您可以隐式地将函数的参数“扩展”到子计算:
nextThree = (,,) <$> (+ 1) <*> (+ 2) <*> (+ 3)
-- or
nextThree = liftA3 (,,) (+ 1) (+ 2) (+ 3)
nextThree 5 == (6, 7, 8)
uncurry' f = f <$> fst <*> snd
-- or
uncurry' f = liftA2 f fst snd
uncurry' (+) (1, 2) == 3
liftM2 (==)
的签名是(Monad m, Eq a) => ma -> ma -> m Bool
。 所以这意味着如果我们用id :: b -> b
作为参数调用这个函数,那么它意味着ma
和b -> b
是相同的类型。
m ~ (->) b
保持的事实不是问题,因为(->) r
是Monad
一个实例,实际上在我们看到的GHC.Base源代码中 :
-- | @since 2.01 instance Monad ((->) r) where f >>= k = \\ r -> k (fr) r
这只有m ~ (->) b
才有意义。 这里箭头(->)
是一个类型构造函数, (->) ab
与a -> b
相同。
所以这意味着如果我们计算liftM2 (==) id
的类型,我们得出以下结果:
liftM2 (==) :: m a -> m a -> m Bool
id :: (b -> b)
-------------------------------------------
m ~ (->) b, a ~ b
这意味着liftM2 (==) id
的输出类型是liftM2 (==) id :: (Monad m, Eq a) => ma -> m Bool
,但我们需要用我们的知识“专门化”这个获得: ma
是(->) b
和a
是b
类型,所以:
liftM2 (==) id :: (Monad m, Eq a) => m a -> m Bool
-> liftM2 (==) id :: (Monad m, Eq a) => (b -> a) -> (b -> Bool)
-> liftM2 (==) id :: Eq b => (b -> b) -> (b -> Bool)
-> liftM2 (==) id :: Eq b => (b -> b) -> b -> Bool
简而言之,该函数仍然是“monadic”,虽然通过使用id
,您已经选择了一个特定的monad,因此该函数不再适用于所有类型的monad,只适用于(->) r
monad。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.