樣板講座
首先,假裝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