Haskell:为什么“ id”使该功能不再单调?

use*_*476 5 haskell

我试图理解为什么id在下面序列的最后一行中添加会消除单声道方面:

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>
Run Code Online (Sandbox Code Playgroud)

如何添加id :: a -> a以最后一行的方式更改签名?

Jon*_*rdy 8

您正在将类型固定为特定的Monad实例,即“函数阅读器” monad(instance Monad ((->) a))。

id :: a -> a并且您尝试将其用作类型为的参数的参数m a,因此:

m a  ~  a -> a
m a  ~  (->) a a
m a  ~  ((->) a) a
m    ~  (->) a
a    ~  a
Run Code Online (Sandbox Code Playgroud)

签名的其余部分是:

m a -> m Bool
Run Code Online (Sandbox Code Playgroud)

由于m ~ (->) a,结果类型为:

(->) a a -> (->) a Bool
(a -> a) -> (a -> Bool)
(a -> a) -> a -> Bool
Run Code Online (Sandbox Code Playgroud)

(加上使用的Eq a约束==。)

这在无点代码中很有用,尤其是在使用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
Run Code Online (Sandbox Code Playgroud)