[编辑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的包装,对吗?
答案 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