定型講演
まず、ふりをしてunsafePerformIO
が存在しません。次に、より完全なコードスニペットを提示してください、私は答えようとしますが、結果として途中で前提を作るでしょう。
ザ・ウォークスルー
あなたは提示:
gameLoop :: User -> IO()
gameLoop initUser = displayPosition initUser >> gameLoop (applyAction initUser)
をだから、あなたがdisplayPosition :: User -> IO()
のためのいくつかの定義を持っている必要がありそうです。次に、type UserAction = User -> User
と思われるUserAction
を使用します。、
applyAction = maybe id (unsafePerformIO (fmap getUserAction getLine))
代わりの魔法のIOを作る:
applyAction :: UserAction
は今、あなたは突然
User -> IO User
種類をもたらす、あなたは
User -> User
タイプをしたいが、代わりにあなたがしたいのですが、この
IO
ありません実現しますそして完全に危険な状態で、ユーザーが定義することができ可能性が消える:
gameLoop
に戻って
が
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
、種類を変更してwをしています期待値が:: User
の場合、applyAction initUser :: IO 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
もっと書き換え
それは1つの解決策でしたが、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」から「forever」を見ることをお勧めします。 –
それは同じモナドを何度も繰り返し実行していませんか?私はinitUserに沿って渡したい。 – hgiesel