在haskell中实现StateT的Monad时无法理解编译器错误

9bfwbjaz  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(139)

我正在通过fp-course学习haskell。本练习要求为StateT实现Monad
https://github.com/Nero5023/fp-course-solution/blob/f95a1a8c1b95dbe63015168f4fe4388854cd4a32/src/Course/StateT.hs#L89
我不知道为什么我的实现使编译器错误。有人能帮忙吗?

instance Monad k => Monad (StateT s k) where
  (=<<) ::
    forall a b. (a -> StateT s k b)
    -> StateT s k a
    -> StateT s k b
  (=<<) f sta = StateT $ \s -> let kas = runStateT sta s
                                   stb = (kas >>= (\(a, s1) -> (f a)))
                               in  runState stb s1

错误如下。let in会出错吗?

src/Course/StateT.hs:94:17: error:
    • Couldn't match type ‘k’ with ‘(,) b’
      ‘k’ is a rigid type variable bound by
        the instance declaration at src/Course/StateT.hs:89:10
      Expected type: StateT s k b
        Actual type: StateT s ((,) b) b
    • In the expression:
        StateT
        $ \ s
            -> let
                 kas = ...
                 ....
               in runState stb s1
      In an equation for ‘=<<’:
          (=<<) f sta = StateT $ \ s -> let ... in runState stb s1
      In the instance declaration for ‘Monad (StateT s k)’
    • Relevant bindings include
        sta :: StateT s k a (bound at src/Course/StateT.hs:94:11)
        f :: a -> StateT s k b (bound at src/Course/StateT.hs:94:9)
        (=<<) :: (a -> StateT s k b) -> StateT s k a -> StateT s k b
          (bound at src/Course/StateT.hs:94:3)

src/Course/StateT.hs:95:65: error:
    • Couldn't match type ‘k’ with ‘StateT s k’
      ‘k’ is a rigid type variable bound by
        the instance declaration at src/Course/StateT.hs:89:10
      Expected type: k b
        Actual type: StateT s k b
    • In the expression: (f a)
      In the second argument of ‘(>>=)’, namely ‘(\ (a, s1) -> (f a))’
      In the expression: (kas >>= (\ (a, s1) -> (f a)))
    • Relevant bindings include
        s1 :: s (bound at src/Course/StateT.hs:95:57)
        stb :: k b (bound at src/Course/StateT.hs:95:36)
        kas :: k (a, s) (bound at src/Course/StateT.hs:94:36)
        s :: s (bound at src/Course/StateT.hs:94:27)
        sta :: StateT s k a (bound at src/Course/StateT.hs:94:11)
        f :: a -> StateT s k b (bound at src/Course/StateT.hs:94:9)
        (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds)

src/Course/StateT.hs:96:49: error:
    • Variable not in scope: s1 :: (b, s)
    • Perhaps you meant ‘s’ (line 94)
Failed, modules loaded: Course.Applicative, Course.Cheque, Course.Comonad, Course.Compose, Course.Contravariant, Course.Core, Course.ExactlyOne, Course.Extend, Course.FastAnagrams, Course.FileIO, Course.Functor, Course.JsonValue, Course.List, Course.Monad, Course.Optional, Course.Parser, Course.Person, Course.State, Course.Validation, Test.Framework.Random.
taor4pac

taor4pac1#

在表达式中:

kas >>= \(a,s1) -> (f a)

>>=运算符的左手参数的类型是k (a, s),但右手参数的类型是(a, s) -> StateT s k b。这与>>=运算符的类型不匹配,它需要两边的单子来匹配,而不是左边的k和右边的StateT s k
您需要将f a :: StateT s k b转换为k (b, s)类型,如果您只需要一个提示,您可以使用runStateT和浮动的s1来完成。
如果你想要完整的答案…
.
.
.
.
你可能想要这样的东西:

(=<<) f sta = StateT $ \s -> let kas = runStateT sta s
                             in  kas >>= \(a, s1) -> runStateT (f a) s1

相关问题