Haskell:如何在编写自己的"绑定"时更好地理解类型?

Neu*_*onQ 1 monads haskell types bind

我试图通过实际尝试手动实现一些使用过的运算符(如>>=(bind))来绕过Haskell的monad .我这样做是为了尝试更好地理解事物,这种努力没有实际用途.但是我从一开始就进入了一堵砖墙,因为在monads的解释中看起来像"代码示例"的代码实际上并不是实际可编译的代码......

当我尝试定义自己的时候,bind我得到了一个类型错误.这段代码:

bind :: IO a -> (a -> IO b) -> IO b
(bind action1 action2) world0 =
    let (a, world1) = action1 world0
        (b, world2) = action2 a world1
    in
        (b, world2)
Run Code Online (Sandbox Code Playgroud)

...给我这些(9是上面代码的第一行):

iom.hs:10:1:
    Couldn't match expected type `t0 -> (t1, t2)'
                with actual type `IO b'
    The equation(s) for `bind' have three arguments,
    but its type `IO a -> (a -> IO b) -> IO b' has only two

iom.hs:11:23:
    Couldn't match expected type `t0 -> (t1, t2)'
                with actual type `IO a'
    The function `action1' is applied to one argument,
    but its type `IO a' has none
    In the expression: action1 world0
    In a pattern binding: (a, world1) = action1 world0

iom.hs:12:23:
    Couldn't match expected type `t2 -> (t0, t1)'
                with actual type `IO b'
    The function `action2' is applied to two arguments,
    but its type `a -> IO b' has only one
    In the expression: action2 a world1
    In a pattern binding: (b, world2) = action2 a world1
Run Code Online (Sandbox Code Playgroud)

我刚刚从http://www.haskell.org/haskellwiki/IO_inside的示例开始,只是用>>=bind 替换以防止名称冲突并将其定义为函数而不是infox运算符.这是作为解释提供的示例(复制粘贴):

(>>=) :: IO a -> (a -> IO b) -> IO b
(action1 >>= action2) world0 =
   let (a, world1) = action1 world0
       (b, world2) = action2 a world1
   in (b, world2)
Run Code Online (Sandbox Code Playgroud)

现在,如果我替换最后一行,return (b, world2)我得到这个:

iom.hs:10:1:
    Couldn't match expected type `t0 -> m0 (t1, t2)'
                with actual type `IO b'
    The equation(s) for `bind' have three arguments,
    but its type `IO a -> (a -> IO b) -> IO b' has only two

iom.hs:11:23:
    Couldn't match expected type `t0 -> (t1, t2)'
                with actual type `IO a'
    The function `action1' is applied to one argument,
    but its type `IO a' has none
    In the expression: action1 world0
    In a pattern binding: (a, world1) = action1 world0

iom.hs:12:23:
    Couldn't match expected type `t2 -> (t0, t1)'
                with actual type `IO b'
    The function `action2' is applied to two arguments,
    but its type `a -> IO b' has only one
    In the expression: action2 a world1
    In a pattern binding: (b, world2) = action2 a world1
Run Code Online (Sandbox Code Playgroud)

dup*_*ode 6

之所以发生这种情况,是因为教程中的IO使用虚构(虽然受到真实的启发)定义IO(详见第3节):

type IO a  =  RealWorld -> (a, RealWorld)
Run Code Online (Sandbox Code Playgroud)

使用此定义IO a实际上是函数类型的同义词,因此错误消息引用的额外参数不会成为问题.实际IO类型是抽象的,因此您无法在代码中查看或使用它实际构成的内容.

如果您想自己运行文章代码,请在重命名IO为eg时使用该定义,MyIO并相应地更改其他定义.