【问题标题】:Why this Either-monad code does not type check?为什么这个 Either-monad 代码不进行类型检查?
【发布时间】:2011-02-04 22:02:10
【问题描述】:
instance Monad (Either a) where
     return = Left
     fail = Right
     Left x >>= f = f x
     Right x >>= _ = Right x

“baby.hs”中的这段代码片段导致了可怕的编译错误:

Prelude> :l baby
[1 of 1] Compiling Main             ( baby.hs, interpreted )

baby.hs:2:18:
Couldn't match expected type `a1' against inferred type `a'
  `a1' is a rigid type variable bound by
       the type signature for `return' at <no location info>
  `a' is a rigid type variable bound by
      the instance declaration at baby.hs:1:23
In the expression: Left
In the definition of `return': return = Left
In the instance declaration for `Monad (Either a)'

baby.hs:3:16:
Couldn't match expected type `[Char]' against inferred type `a1'
  `a1' is a rigid type variable bound by
       the type signature for `fail' at <no location info>
  Expected type: String
  Inferred type: a1
In the expression: Right
In the definition of `fail': fail = Right

baby.hs:4:26:
Couldn't match expected type `a1' against inferred type `a'
  `a1' is a rigid type variable bound by
       the type signature for `>>=' at <no location info>
  `a' is a rigid type variable bound by
      the instance declaration at baby.hs:1:23
In the first argument of `f', namely `x'
In the expression: f x
In the definition of `>>=': Left x >>= f = f x

baby.hs:5:31:
Couldn't match expected type `b' against inferred type `a'
  `b' is a rigid type variable bound by
      the type signature for `>>=' at <no location info>
  `a' is a rigid type variable bound by
      the instance declaration at baby.hs:1:23
In the first argument of `Right', namely `x'
In the expression: Right x
In the definition of `>>=': Right x >>= _ = Right x
Failed, modules loaded: none.

为什么会这样?我怎样才能使这段代码编译? 感谢您的帮助~

我明白了。我调整了代码以查看它的编译:

instance Monad (Either a) where
     return = Right
     Left a >>= f = Left a
     Right x >>= f = f x

编译成功! 但是......还有更多问题:

instance Monad (Either a)

使 'Either a' 成为一个 monad,我得到了 'return = Right'...我怎么能得到 'return = Left'? 我试过这个但失败了:

instance Monad (`Either` a) where
     return = Left
     Right a >>= f = Right a
     Left x >>= f = f x

或: 实例 Monad (\x -> 任意一个 x a)

根本不编译!

【问题讨论】:

标签: haskell monads either


【解决方案1】:

大部分混淆源于 Left 和 Right 倒置使用的事实。仅考虑返回的类型,其来自 Monad 类型类的类型如下:

return :: (Monad m) => b -> m b

您正在尝试为 m = Either a 定义一个实例,因此 return 应该具有类型:

return :: b -> Either a b

您将其定义为 Left,其类型为:

Left :: a -> Either a b

注意-&gt; 左侧的不同之处。

【讨论】:

  • 我明白了。我调整了代码以查看它编译: instance Monad (Either a) where return = Right Left a >>= f = Left a Right x >>= f = f x 它编译成功!但是......还有一个问题:instance Monad (Either a) 使 'Either a' 成为一个 monad,我得到了 'return = Right'......我怎么能得到 'return = Left'?我试过这个但失败了: instance Monad (Either a) where return = Left Right a >>= f = Right a Left x >>= f = fx or: instance Monad (\x -> Either xa) 没有根本不编译!
  • 你不能用 return=Left 使 Either a 成为 Monad。 Haskell Monad 是一个参数的类型类(我们以b 为例),它匹配return 的参数类型。这与 Haskell 对 Either 的定义不兼容,后者是一个类型类,其中最后一个参数是 Right 的参数。您只能通过使用交换类型参数重新定义 Either 来实现您想要的,就像在 data Either a b = Left b | Right a 中一样,但是您将与所有标准库对 Either 值的支持不兼容。
【解决方案2】:
  1. return 的类型应为 forall b. b -&gt; Either a b,但 Left 的类型为 forall c. a -&gt; Either a c。您可能想要就在这里。
  2. fail 应该有 forall b. String -&gt; Either a b 类型,但是 Right 有 forall b. b -&gt; Either a b 类型,所以如果 b=String 使得 String -&gt; Either a String 不适合。
  3. &gt;&gt;= 应该具有 Either a b -&gt; (b -&gt; Either a c) -&gt; Either a c 类型,但 Right x &gt;&gt;= _ = Right x 始终返回 Either a b 类型的值,而不是 Either a c
  4. Left x &gt;&gt;= f = f x 不起作用,因为 x 的类型为 a,但 f 的类型为 b -&gt; c

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    • 2016-06-04
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多