私は、セルのグリッドを含み、グリッドをナビゲートするためにランダムな動きを選択する「AI-AModernApproach」本の問題2.8を解決しようとしています。
2.7 X mの長方形の部屋の環境を実装します。ここで、各正方形には5%の確率で汚れが含まれ、nとmは8から15までの範囲からランダムに選択されます。
2.8帰宅の要件を無視して、演習2.7の環境用の純粋な反射エージェントを設計および実装し、そのパフォーマンスを測定します。
そのため、2つの状態モナドを使用しました。1つGrid
は状態として、もう1つは状態として使用しStdGen
ました。コードはエラーなしでコンパイルされますが、GHCiから実行すると、スタックして戻りません。
コードの関連部分:
サポートコード
type RandomState = State StdGen
makeGrid :: (Int, Int) -> (Int, Int) -> Float -> RandomState Grid
doAction :: Action -> Cleaner -> State Grid Cleaner
getRandomR :: Random a => (a, a) -> RandomState a
getRandomR limits = do
gen <- get
let (val, gen') = randomR limits gen
put gen'
return val
chooseAction :: Percepts -> RandomState Action
chooseAction percepts
| PhotoSensor `elem` percepts = return SuckDirt
| InfraredSensor `elem` percepts = return TurnOff
| TouchSensor `elem` percepts = return TurnLeft
| otherwise = do
r <- getRandomR ((1, 3) :: (Int, Int))
case r of
1 -> return GoForward
2 -> return TurnRight
3 -> return TurnLeft
メインコード
runCleaner :: Int -> Cleaner -> StateT Grid RandomState Cleaner
runCleaner turnsLeft cleaner@(Cleaner _ _ _ ph _) =
if turnsLeft == 0
then return cleaner
else do
grid <- get
gen <- lift $ get
cleaner <- case ph of
[] -> do
let (cleaner, grid) = runState (doAction GoForward cleaner) grid
put grid
return cleaner
_ -> do
let (action, gen) = runState (chooseAction (head ph)) gen
lift $ put gen
let (cleaner, grid) = runState (doAction action cleaner) grid
put grid
return cleaner
case clState cleaner of
Off -> return cleaner
On -> runCleaner (turnsLeft - 1) cleaner
simulateOnGrid :: Int -> Grid -> StdGen -> (Cleaner, Grid)
simulateOnGrid maxTurns grid gen =
evalState (runStateT (runCleaner maxTurns cleaner) grid) gen
where cleaner = createCleaner (fromJust $ cell (0,0) grid) East
simulateOnGrid
私はこのようにGHCiから関数を呼び出します:
> gen <- newStdGen
> let grid = evalState (makeGrid (8,15) (8,15) 0.05) gen
> simulateOnGrid 5 grid gen
そしてコードは次の行でスタックします:
let (cleaner, grid) = runState (doAction GoForward cleaner) grid
これは、コードにトレースを入れることで確認しました。関数の呼び出しdoAction
は発生しません。
runState
関数内での使用に問題があるようですがrunCleaner
、理由がわかりません。
その理由と、この問題を解決する方法があるかどうかを説明してください。
また、runState
モナディック関数の内部で使用することは私には間違っていると感じます。それを行うためのより良い方法があるかどうかを提案してください。