如何在Haskell中创建结合状态和错误的monad
我正在尝试创建一个结合了状态和错误处理的monad,如下所示如何在Haskell中创建结合状态和错误的monad,haskell,Haskell,我正在尝试创建一个结合了状态和错误处理的monad,如下所示 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,
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 ()
当我编译时,我收到这个错误,我不知道如何修复它:
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
| ^
我做错了什么?我认为问题在于很难匹配案例的两个结果
Expected type: (Result b e, s)
Actual type: (Result a e, s)
比如强制a
变成b
,或者类似的东西,但我不知道如何解决这个问题
此外,我还收到以下错误:
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
,因此我希望能在这里得到一些指导
谢谢您的错误已通过将代码更改为
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
以及明显的函子
和应用
实例
instance Functor .... where
fmap = liftM
instance Applicative .... where
(<*>) = ap
pure = return
在箭头的左边和右边有不同的类型。因为它在错误消息中抱怨
Expected type: (Result b e, s)
Actual type: (Result a e, s)
当您使用变量时,箭头两侧的变量将相同。因此e
重用相同的值,但Error e
根据需要创建适当类型的新值。我们确实需要新的类型,正如(>>=)
的签名所要求的:
关于应用程序,也必须定义它。您只需将您的return
放在应用程序实例中的pure
名称下,然后在那里添加ab=apab
。然后在Monad中havereturn=pure
。所以这就解决了这个问题。为什么不把StateT
和或者ExceptT
和State
结合起来呢?@MarkSeemann因为我是哈斯凯尔的新手,正试图创建他的第一个单子,现在还不想搞乱单子变形金刚。此外,我不确定monad transformer版本是否更易于编写或在性能方面更高效。这是一个很好的理由:)知道这些monad transformer的存在可能会有用,不过,以后再说。@MarkSeemann是的,Mark,我知道它们的存在,还有“comonads”、“free monad”和各种“costrangenads”,但一次只能做一件事;-)好的,你帮了很多忙。请参阅问题中我的更新代码。现在,您可以帮助我使用fmap
定义来简化monad绑定操作符的实现吗?被迫定义一个函子,而不利用它来简化monad实现,似乎是没有用的。这两个代码看起来非常相似,所以我想还有一些事情要做。否则,函子需要什么?不看,你真的应该问新问题,如果你的问题有实质性的变化。我真的建议你展开你的编辑,然后问一个新问题。谢谢。哦,我考虑过了,但决定在这个问题上这样做,因为所有的东西都在一个地方。我是否仍应将此部分移至另一个新问题中,并在新问题中引用此问题?是的,您应回滚编辑,提出新的“后续”问题,并将此问题的链接作为背景。我现在就给你滚回去。:)完成后,您可以看到新问题。
Expected type: (Result b e, s)
Actual type: (Result a e, s)
Monad m => m a -> (a -> m b) -> m b
-- ^^ ^^