样板讲座
首先,假装unsafePerformIO
不存在。其次,下一次请提出一个更完整的代码片段,我会尽力回答,但会一直做出假设。
步行通过的
您呈现:
gameLoop :: User -> IO()
gameLoop initUser = displayPosition initUser >> gameLoop (applyAction initUser)
因此,看来你必须有一些定义displayPosition :: User -> IO()
。然后下面你使用UserAction
这似乎是type UserAction = User -> User
。
applyAction :: UserAction
现在你突然意识到你不想User -> User
型,而是有这个IO
你想要做的,产生User -> IO User
类型:
applyAction = maybe id (unsafePerformIO (fmap getUserAction getLine))
不是使IO神奇,和完全不安全,消失,你可以可以定义:
applyAction :: User -> IO User
applyAction previousUser =
do ln <- getLine
case getUserAction ln of
Nothing -> -- You never said what to do here.
-- This is the same logical issue as the missing
-- argument to your call to `maybe` above.
return previousUser -- XXX do something correct!
Just act -> return act
回过头来看看这个gameLoop
,类型已经改变和W e不能使用applyAction initUser :: IO User
,期望值为:: User
。我们可以,但是,使用一元绑定或做标记法:
gameLoop initUser =
do displayPosition initUser
newUser <- applyAction initUser
gameLoop newUser
这只是语法糖:
gameLoop initUser = displayPosition initUser >> applyAction initUser >>= \newUser -> gameLoop newUser
或者干脆:
gameLoop initUser = displayPosition initUser >> applyAction initUser >>= gameLoop
更多重复写
这是一个解决方案,但它会很好,保持applyAction
函数无效(无IO),所以你可以测试它,更容易重构该程序。而不是在那里得到一条线那么我们如何得到一条线在循环中,并通过它:
gameLoop initUser =
do displayPosition initUser
command <- getLine
newUser <- applyAction command initUser
gameLoop newUser
applyAction :: String -> User -> User
applyAction cmd oldState = maybe oldState id (getUserAction ln)
我建议你看看从'Control.Monad'永远''。 –
这不是一遍又一遍地执行相同的monad吗?我想传递initUser。 – hgiesel