简体   繁体   English

Haskell:为什么'id'使这个函数不再是monadic?

[英]Haskell: why does 'id' make this function no longer monadic?

I am trying to understand why adding id in the last line of the sequence below removes the monadic aspect: 我试图理解为什么在下面的序列的最后一行添加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>

How does adding id :: a -> a change the signature in the way it does in the last line ? 如何添加id :: a -> a以最后一行的方式更改签名?

You're fixing the type to a particular Monad instance, namely the “function reader” monad ( instance Monad ((->) a) ). 您正在将类型修改为特定的Monad实例,即“函数阅读器”monad( instance Monad ((->) a) )。

id :: a -> a and you are attempting to use it as an argument to a parameter of type ma , so: id :: a -> a并且您尝试将其用作ma类型参数的参数,因此:

m a  ~  a -> a
m a  ~  (->) a a
m a  ~  ((->) a) a
m    ~  (->) a
a    ~  a

The remainder of the signature is: 签名的其余部分是:

m a -> m Bool

And since m ~ (->) a , the resulting type is: 由于m ~ (->) a ,结果类型为:

(->) a a -> (->) a Bool
(a -> a) -> (a -> Bool)
(a -> a) -> a -> Bool

(Plus the Eq a constraint from the use of == .) (加上Eq a使用== Eq a约束。)

This is useful in pointfree code, particularly using the Applicative instance, since you can implicitly “spread” the argument of a function to subcomputations: 这在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

The signature of liftM2 (==) is (Monad m, Eq a) => ma -> ma -> m Bool . liftM2 (==)的签名是(Monad m, Eq a) => ma -> ma -> m Bool So that means that if we call this function with id :: b -> b as argument, then it means that ma and b -> b are the same type. 所以这意味着如果我们用id :: b -> b作为参数调用这个函数,那么它意味着mab -> b是相同的类型。

The fact that m ~ (->) b holds is not a problem since (->) r is an instance of Monad , indeed in the GHC.Base source code we see: m ~ (->) b保持的事实不是问题,因为(->) rMonad一个实例,实际上在我们看到的GHC.Base源代码中

 -- | @since 2.01 instance Monad ((->) r) where f >>= k = \\ r -> k (fr) r 

This only makes sense if m ~ (->) b . 这只有m ~ (->) b才有意义。 Here the arrow (->) is a type constructor, and (->) ab is the same as a -> b . 这里箭头(->)是一个类型构造函数, (->) aba -> b相同。

So it means that if we calculate the type of liftM2 (==) id , we derive the following: 所以这意味着如果我们计算liftM2 (==) id的类型,我们得出以下结果:

liftM2 (==)    ::  m a     -> m a -> m Bool
            id :: (b -> b)
-------------------------------------------
m ~ (->) b, a ~ b

This thus means that the output type of liftM2 (==) id is liftM2 (==) id :: (Monad m, Eq a) => ma -> m Bool , but we need to "specialize" this with the knowledge we obtained: that ma is (->) b and a is the same type as b , so: 这意味着liftM2 (==) id的输出类型是liftM2 (==) id :: (Monad m, Eq a) => ma -> m Bool ,但我们需要用我们的知识“专门化”这个获得: ma(->) bab类型,所以:

   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

In short the function is still "monadic", although by using id , you have selected a specific monad, and thus the function is no longer applicable to all sorts of monads, only to the (->) r monad. 简而言之,该函数仍然是“monadic”,虽然通过使用id ,您已经选择了一个特定的monad,因此该函数不再适用于所有类型的monad,只适用于(->) r monad。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM