如何在Haskell中创建结合状态和错误的monad [英] How to create a monad that combines state and error in Haskell

查看:79
本文介绍了如何在Haskell中创建结合状态和错误的monad的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个将状态和错误处理结合在一起的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

添加明显的FunctorApplicative实例,

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆