如何在Haskell中创建结合状态和错误的monad [英] How to create a monad that combines state and error in Haskell
问题描述
我正在尝试创建一个将状态和错误处理结合在一起的monad,
I am trying to create a monad that combines state and error processing, like this
import Control.Monad
data Result a e = Ok a | Error e
newtype StateError s e a = StateError { runStateError :: s -> (Result a e, s) }
instance Monad (StateError s e) where
return x = StateError $ \s -> (Ok x, s)
m >>= f = StateError $
\s -> case runStateError m s of
(Ok x, s') -> runStateError (f x) s'
e -> e
get = StateError $ \s -> ((Ok s), s)
put s = StateError $ \_ -> ((Ok ()), s)
main = return ()
编译时,我收到此错误,我不知道如何解决:
When I compile, I receive this error, which I do not know how to fix:
StateError.hs:13:18: error:
• Couldn't match type ‘a’ with ‘b’
‘a’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b.
StateError s e a -> (a -> StateError s e b) -> StateError s e b
at StateError.hs:10:5-7
‘b’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b.
StateError s e a -> (a -> StateError s e b) -> StateError s e b
at StateError.hs:10:5-7
Expected type: (Result b e, s)
Actual type: (Result a e, s)
• In the expression: e
In a case alternative: e -> e
In the expression:
case runStateError m s of
(Ok x, s') -> runStateError (f x) s'
e -> e
• Relevant bindings include
e :: (Result a e, s) (bound at StateError.hs:13:13)
f :: a -> StateError s e b (bound at StateError.hs:10:9)
m :: StateError s e a (bound at StateError.hs:10:3)
(>>=) :: StateError s e a
-> (a -> StateError s e b) -> StateError s e b
(bound at StateError.hs:10:5)
|
13 | e -> e
| ^
我在这里做错了什么?我认为问题在于难以匹配case
What am I doing wrong here? I think the problem is the difficulty of matching the two results of the case
Expected type: (Result b e, s)
Actual type: (Result a e, s)
喜欢强制a
成为b
或类似的东西,但是我不知道如何解决这个问题.
like force a
to be a b
, or something alike, but I don't know how to solve this.
此外,我还收到此错误:
In addition, I am also receiving this error:
StateError.hs:7:10: error:
• No instance for (Applicative (StateError s e))
arising from the superclasses of an instance declaration
• In the instance declaration for ‘Monad (StateError s e)’
|
7 | instance Monad (StateError s e) where
| ^^^^^^^^^^^^^^^^^^^^^^
这要求我实例化Applicative
,因此,我希望这里提供一些指导.
This asks me to instantiate Applicative
, so I would appreciate some guidance on what to do here.
谢谢
推荐答案
通过将代码更改为
m >>= f = StateError $
\s -> case runStateError m s of
(Ok x, s1) -> runStateError (f x) s1
(Error e, s1) -> (Error e, s1)
-- or:
-- (Error e, s1) -> (Error e, s) -- also works
-- not:
-- e -> e -- this doesn't
和添加明显的Functor
和Applicative
实例,
instance Functor .... where
fmap = liftM
instance Applicative .... where
(<*>) = ap
pure = return
Error e :: Result a e
是多态的,
data Result a e = Ok a | Error e
因此在该箭头的左侧和右侧具有不同的类型.由于它在错误消息中抱怨,
so has different types on the left and on the right of that arrow. As it complaints in the error message,
Expected type: (Result b e, s)
Actual type: (Result a e, s)
当您使用变量时,这使得箭头两侧的相同相同.因此,e
重用了相同的值,但是Error e
根据需要创建了适当类型的新值.而且我们确实需要(>>=)
签名所要求的新类型:
when you use a variable, that makes it be the same on the both sides of the arrow. So e
reuses the same value, but Error e
creates new value of the appropriate type as needed. And we do need the new type, as demanded by the signature of (>>=)
:
Monad m => m a -> (a -> m b) -> m b
-- ^^ ^^
这篇关于如何在Haskell中创建结合状态和错误的monad的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!