MonadState陷入无限递归循环

时间:2018-03-24 21:25:30

标签: haskell monads monad-transformers

[编辑3]

我最终确定了问题:我为MonadState实例添加了put方法:

instance MonadState CPUState VM where
    get = VM get
    put s = do
              liftIO $ putStrLn $ "Modifying state"
              liftIO $ putStrLn.show $ (ip s)
              state (\_ -> ((),s))

无论何时需要更新状态,都会启动无限循环:

let s' = (cpuState { ip = (ip cpuState) + 1 })
put s'

我不确定为什么......任何人都可以请他们澄清为什么它继续以递归方式调用put方法?

[编辑2]

现在我知道为什么它会挂起,而这一切都归功于这一行:

modify $ \s -> (cpuState { globalMemory = newGlobalMemory, ip = currentIP + 1 })

在我创建newtype之前,这完全正常工作......我如何在MonadState实例上实现相同的方法?

[编辑1]

谢谢chi!我实际上做了类似的事情:

newtype VM a = VM{
    unwrapVM :: RWST [Quadruple] [String] (CPUState) IO a
} deriving (Functor, Applicative, Monad, MonadIO,
             MonadRWS [Quadruple] [String] CPUState)

instance MonadReader [Quadruple] VM where
    ask = VM ask

instance MonadWriter [String] VM where
    tell = VM . tell

instance MonadState CPUState VM where
    get = VM get

这是编译,但是当我评估RWST时,它只是无限期挂起

我实际上尝试过你的方式,但是我得到以下编译错误(即使使用GeneralizedNewtypeDeriving):

• Expecting one more argument to ‘VM’
  Expected a type, but ‘VM’ has kind ‘* -> *’
• In the first argument of ‘MonadWriter’, namely ‘VM’

[原始问题]

给出一个包装RWST的新类型:

newtype VM a = VM{
    unwrapVM :: RWST [Quadruple] [String] (CPUState) IO a
} deriving (Functor, Applicative, Monad, MonadIO)

为什么不能做这样的事情?

startVM :: [Quadruple] -> Memory -> Memory -> IO ()
startVM quads globalMemory localMemory = 
    do 
      (a,w) <- evalRWST (unwrapVM $ runVM) quads (setInitialCPUState globalMemory localMemory) 
      mapM_ (putStrLn) $ w 

runVM :: VM ()
runVM = do
          quadruples <-  ask     . . . .    [1] 
          cpuState <-  get       . . . .    [2]
          return ()

Haskell在runVM中抱怨没有MonadReader [1]和MonadState [2]的实例,但显然不是这样,因为VM只是RWST的包装,对吗?

2 个答案:

答案 0 :(得分:1)

您需要明确要求继承所需的实例。

newtype VM a = VM{
    unwrapVM :: RWST [Quadruple] [String] (CPUState) IO a
} deriving (Functor, Applicative, Monad, MonadIO, MonadState, MonadReader)
                                               -- ^^^^^^^^^^^^^^^^^^^^^^^

为此,您可能需要扩展程序GeneralisedNewtypeDeriving

您需要明确继承这些实例,否则您可以定义自己的

instance MonadState VM where ...
instance MonadReader VM where ...

实际上,在T下包装现有类型newtype W只是为W提供不同 非常 >实例而不是T的实例。

答案 1 :(得分:0)

无限循环是由于我在put中调用状态。我刚把它改成了:

instance MonadState CPUState VM where
    get = VM get
    put s = VM . put $ s 

对于任何想要隐藏嵌套monad变换器的人来说,这是要走的路:

newtype VM a = VM{
    unwrapVM :: RWST [Quadruple] [String] (CPUState) IO a
} deriving (Functor, Applicative, Monad, MonadIO,MonadRWS [Quadruple] [String] CPUState)

instance MonadReader [Quadruple] VM where
    ask = VM ask

instance MonadWriter [String] VM where
    tell = VM . tell

instance MonadState CPUState VM where
    get = VM get
    put s = VM . put $ s