2011-10-04 48 views
3

我想解决“AI - 一种现代方法”的书中涉及网格单元格,并选择随机移动浏览网格的问题2.8。运行状态内状态一元功能不工作

2.7实施为一个N×M的矩形室,其中每个正方形 具有含有污垢的5%的机会的环境中,和n和m是在 随机选自范围为8〜15,包括端值。

2.8设计并实现一个纯反射代理环境 练习2.7,忽略返回家的要求,并测量其性能 。

所以我用了两个状态单元 - 一个用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 [email protected](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函数的调用永远不会发生。

这个问题似乎是runCleaner函数中runState的使用,但是我找不到任何理由。

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

另外,使用runState里面的monadic函数对我来说感觉不对。请建议是否有更好的方法来做到这一点。

回答

6

let的右手边结合,被绑定的名字都在范围内,所以,当你写

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