传递给列表monad bind的函数可以是没有编译器错误的标识

Mic*_*mza 1 monads haskell functional-programming ghci

将列表monad绑定函数应用于简单列表和标识函数时:

[[1,2],[3,4]] >>= \x -> x
Run Code Online (Sandbox Code Playgroud)

我明白了

[1,2,3,4]
Run Code Online (Sandbox Code Playgroud)

但是,Monad类型的定义:

class Monad m where
  (>>=) :: m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)

似乎建议函数,在我的情况下lambda函数\x -> x,应该返回一个不同的类型传入.我希望在这种情况下编译器错误,但我没有.我在ghci中运行它.

为什么编译器在这种情况下不会抛出错误?

Pet*_*lák 6

身份功能id :: a -> a,或明确\x -> x是多态的.这意味着它可以专门用于通过替换某些类型来构造的任何类型a.

在您的情况下(>>= id),编译器会查看第二个参数的类型

(>>=) :: m c -> (c -> m d) -> m d
Run Code Online (Sandbox Code Playgroud)

并在类型id和尝试统一他们:

a -> a    -- id
c -> m d  -- the second argument of >>=
Run Code Online (Sandbox Code Playgroud)

当我们替换a = m d和替换时,这是最通用的方式c = m d.所以id表达式中最常见的类型(>>= id)

id :: m d -> m d
Run Code Online (Sandbox Code Playgroud)

并且整个表达式的类型是

(>>= id) :: (Monad m) => m (m d) -> m d
Run Code Online (Sandbox Code Playgroud)

这是join功能.


Tar*_*mil 5

a,m并且b是类型变量,没有任何东西阻止在给定情况下a等于m b.这是多态的思想:如果事情已键入a没有任何更多的约束a,那么它也有型Int,和[[Bool]]c -> [Int] -> d,和(喜欢这里)m b.

因此,对于这个特定的呼叫,a ~ [Int],b ~ Int,m ~ [],因此,(>>=)"S型[[Int]] -> ([Int] -> [Int]) -> [Int].