仪器状态单子

时间:2019-09-02 21:33:03

标签: haskell

我正在尝试为Monad提供MonadStateState'实例,以计算(>>=), return, getput操作的数量。

data Counts = Counts { binds   :: Int
                 , returns :: Int
                 , gets    :: Int
                 , puts    :: Int
                 }

newtype State' s a = State' { runState' :: (s, Counts) -> (a, s, Counts) }

这就是我已经做过的,据我了解发生了什么,这段代码应该可以工作:

instance Monad State' where
  return     = State' ( \(s, counts) -> (x, s, counts mappend oneReturn))
  (>>=) st f = State' ( \(s, counts) -> let (x, s', counts') = runState' (s, counts) in runState' ((f x), (s', counts' mappend oneBind)) )

instance Monad m => MonadState m State' where
   get    = State' ( \(s, counts) -> (s, s, counts mappend oneGet) )
   put st = State' ( \(s, counts) -> ((), st, counts mappend onePut) )

但是我收到此错误消息:

  

期待‘State'’的另一个论点
  预期种类为‘* -> *’,但是‘State'’的种类为‘* -> * -> *’

为什么?

1 个答案:

答案 0 :(得分:4)

要点在句子中

Expected kind ‘* -> *’, but ‘State'’ has kind ‘* -> * -> *’

如果您使用State'命令通过GHCi检查:k的类型,您将看到State'的类型为* -> * -> *,这简单地说就是需要对其进行参数设置两种类型的*类型产生最终的*类型。如您所见,Monad仅限于* -> *。例如MaybeMonad,而Maybe Int不是。

要解决此问题,您需要将状态类型应用于State',然后才能将其声明为Monad:

instance Monad (State' s) where

第二部分中的错误有点概念化–声明中的m是什么? MonadStateMonad的子类,因此MonadState的每个实例也是Monad的实例。考虑到这一点,正确的符号应该有意义:

instance MonadState s (State' s) where

您不想提及此Monad-它是从类声明派生的。