gpt4 book ai didi

haskell - State Monadic 函数内的 runState 不起作用

转载 作者:行者123 更新时间:2023-12-02 12:01:40 25 4
gpt4 key购买 nike

我正在尝试解决“AI - 现代方法”一书中的问题 2.8,该问题涉及单元格网格并选择随机移动来导航网格。

2.7 Implement an environment for a n X m rectangular room, where each square has a 5% chance of containing dirt, and n and m are chosen at random from the range 8 to 15, inclusive.

2.8 Design and implement a pure reflex agent for the environment of Exercise 2.7, ignoring the requirement of returning home, and measure its performance.

所以我使用了两个状态单子(monad) - 一个以 Grid 作为状态,另一个以 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

我从 GHCi 调用 simulateOnGrid 函数,如下所示:

> 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 函数的调用永远不会发生。

问题似乎是在 runCleaner 函数中使用了 runState,但我找不到任何原因。

请说明原因以及是否有办法解决此问题。

此外,在单子(monad)函数中使用 runState 对我来说感觉不对。如果有更好的方法请提出。

最佳答案

let 绑定(bind)的右侧,被绑定(bind)的名称在范围内,因此当您编写时

let (cleaner, grid) = runState (doAction GoForward cleaner) grid

=右侧的cleanergrid与左侧的相同。当您将操作的输出作为其输入反馈时,这可能会导致无限循环!为了避免这种情况,请为输出使用不同的名称。

let (cleaner', grid') = runState (doAction GoForward cleaner) grid
<小时/>

除此之外,您说这样使用 runState 很奇怪,这是绝对正确的。我认为如果将 doAction 的类型更改为

,您可以大大简化事情
doAction :: Monad m => Action -> Cleaner -> StateT Grid m Cleaner

您没有提供此函数的主体,但我猜测它仍然可以使用这种约束较少的类型签名。

现在您不必再手动获取和放置状态了,因为 doAction 可以直接在您的 monad 中运行,并且 chooseAction 可以运行首先举起它。使用它,您的 case 表达式可以写得更加简洁:

cleaner <- case ph of
[] -> doAction GoForward cleaner
_ -> do action <- lift $ chooseAction (head ph)
doAction action cleaner

关于haskell - State Monadic 函数内的 runState 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7652155/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com