如何在Haskell中创建结合状态和错误的monad

时间:2018-09-26 09:09:31

标签: 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, 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
   |                  ^

我在这里做错了什么?我认为问题在于难以匹配case

的两个结果
      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,因此,我希望您能从此处获得一些指导。

谢谢

1 个答案:

答案 0 :(得分:3)

通过将代码更改为

,可以修复您的错误。
  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

adding明显的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

因此在该箭头的左侧和右侧具有不同的类型。由于它在错误消息中抱怨,

  Expected type: (Result b e, s)
  Actual type: (Result a e, s)

当您使用变量时,这使得箭头两侧的相同相同。因此e重用了相同的值,但是Error e根据需要创建了适当类型的新值。而且我们确实需要(>>=)签名所要求的新类型:

Monad m => m a -> (a -> m b) -> m b
--          ^^                    ^^