为什么这个 Either-monad 代码不进行类型检查?
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'成为单子并且我得到'return = Right'...我怎样才能得到'return = Left'? 我已经尝试过但失败了:
instance Monad (`Either` a) where
return = Left
Right a >>= f = Right a
Left x >>= f = f x
或者: instance Monad (\x -> Either xa)
根本无法编译!
instance Monad (Either a) where
return = Left
fail = Right
Left x >>= f = f x
Right x >>= _ = Right x
this code frag in 'baby.hs' caused the horrible compilation error:
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.
why this happen? and how could I make this code compile ?
thanks for any help~
i see. and i adjusted the code to see it compiles:
instance Monad (Either a) where
return = Right
Left a >>= f = Left a
Right x >>= f = f x
it compiles successfully!
but...for a further more question:
instance Monad (Either a)
makes 'Either a' a monad and i got 'return = Right'...how could i get 'return = Left'?
i've tried this but failed:
instance Monad (`Either` a) where
return = Left
Right a >>= f = Right a
Left x >>= f = f x
or:
instance Monad (\x -> Either x a)
doesn't compile at all!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
大多数混乱源于“左”和“右”被反向使用的事实。仅考虑 return 的类型,它来自 Monad 类型类的类型如下:
您正在尝试为
m
=Either a
定义一个实例,因此 return 应该具有类型:您将其定义为 Left,其类型为:
请注意
->
左侧的不同之处。Most of the confusion stems from the fact Left and Right are used backwards. Considering only the type for return, its type from the Monad typeclass is as follows:
You're trying to define an instance for
m
=Either a
, so return should have type:You're defining it as Left, which has type:
Note how the left hand side of the
->
differs.。 b->要么是b,但Left 的类型是所有c。一个->要么是 c。您可能想要就在这里。
fail
的类型应为forall b。字符串 ->要么是b,但是Right 的类型是所有b。 b->要么是 b
,所以如果b=String
使得String ->;要么是一个不适合的字符串。
>>=
的类型应为ab ->; (b -> 任一 ac) ->要么是 c
,要么是Right x >>>= _ = Right x
始终返回Either a b
类型的值,而不是Either a c
>。Left x >>= f = f x
不起作用,因为 x 的类型为a
,但f
的类型为b -> ; c
.forall b. b -> Either a b
, however Left has typeforall c. a -> Either a c
. You probably want Right here.fail
should have typeforall b. String -> Either a b
, however Right has typeforall b. b -> Either a b
, so ifb=String
that makesString -> Either a String
which does not fit.>>=
should have typeEither a b -> (b -> Either a c) -> Either a c
howeverRight x >>= _ = Right x
always returns a value of typeEither a b
, notEither a c
.Left x >>= f = f x
does not work because x has typea
, butf
has typeb -> c
.