简化一些Haskell代码

时间:2009-08-05 08:03:54

标签: haskell monads

所以我正在为类似跳棋的游戏开发一个minimax实现,以帮助自己更好地学习Haskell。我遇到问题的功能会获取游戏状态列表,并生成即时后续游戏状态列表。像跳棋一样,如果跳跃可用,玩家必须接受它。如果不止一个,玩家可以选择。

在大多数情况下,这适用于列表monad:循环遍历所有输入游戏状态,循环遍历所有可跳跃的弹珠,循环遍历所有大理石的跳跃。这个列表monad很好地将所有列表展平为一个简单的状态列表。

诀窍在于,如果没有找到给定游戏状态的跳转,我需要返回当前游戏状态,而不是空列表。下面的代码是我做到这一点的最佳方式,但对我来说似乎真的很难看。有关如何清理它的任何建议吗?

eHex :: Coord -> Coord -- Returns the coordinates immediately to the east on the board
nwHex :: Coord -> Coord -- Returns the coordinates immediately to the northwest on the board

generateJumpsIter :: [ZertzState] -> [ZertzState]
generateJumpsIter states = do
    ws <- states
    case children ws of
      [] -> return ws
      n@_ -> n
  where 
    children ws@(ZertzState s1 s2 b p) = do
      (c, color)  <- occupiedCoords ws
      (start, end) <- [(eHex, wHex), (wHex, eHex), (swHex, neHex),
                       (neHex, swHex), (nwHex, seHex), (seHex, nwHex)]
      if (hexOccupied b $ start c) && (hexOpen b $ end c)
        then case p of
          1 -> return $ ZertzState (scoreMarble s1 color) s2
                                   (jumpMarble (start c) c (end c) b) p
          (-1) -> return $ ZertzState s1 (scoreMarble s2 color)
                                      (jumpMarble (start c) c (end c) b) p
        else []

编辑:为* Hex函数提供示例类型签名。

2 个答案:

答案 0 :(得分:3)

  

诀窍是,如果没有找到给定游戏状态的跳转,我需要返回当前游戏状态,而不是空列表。

为什么呢?我已经写了几次minimax,我无法想象这种功能的用途。使用

类型的函数不是更好吗?
nextStates :: [ZertzState] -> [Maybe [ZertzState]]

nextStates :: [ZertzState] -> [[ZertzState]]

但是,如果你真的想要返回“下一个状态列表,或者该列表是空的,原始状态”,那么你想要的类型是

nextStates :: [ZertzState] -> [Either ZertzState [ZertzState]]

然后你可以很容易地压扁。

至于如何实现,我建议定义一个类型为

的辅助函数
[ZertzState] -> [(ZertzState, [ZertzState])]

并且可以映射

(\(start, succs) -> if null succs then Left start else Right succs)

结果,以及其他各种事情。

正如弗雷德布鲁克斯所说(释义),一旦你得到了正确的类型,代码实际上就是自己写的。

答案 1 :(得分:1)

不要滥用monad表示法列表,它没有任何重要性。此外,您可以以相同的方式使用列表理解:

do x <- [1..3]
   y <- [2..5]      <=>  [ x + y | x <- [1..3], y <- [2..5] ]
   return x + y

现在用于'简化'

listOfHex :: [(Coord -> Coord,Coord -> Coord)]
listOfHex = [ (eHex, wHex), (wHex, eHex), (swHex, neHex)
            , (neHex, swHex), (nwHex, seHex), (seHex, nwHex)]

generateJumpsIter :: [ZertzState] -> [ZertzState]
generateJumpsIter states =
    [if null ws then ws else children ws | ws <- states]
  where -- I named it foo because I don t know what it do....
    foo True   1  = ZertzState (scoreMarble s1 color) s2
                               (jumpMarble (start c) c (end c) b) p
    foo True (-1) = ZertzState s1 (scoreMarble s2 color)
                               (jumpMarble (start c) c (end c) b) p
    foo False  _  = []
    foo _ _ = error "Bleh"

    children ws@(ZertzState s1 s2 b p) =
      [ foo (valid c hex) p | (c, _)  <- occupiedCoords ws, hex <- listOfHex ]
        where valid c (start, end) =
                 (hexOccupied b $ start c) && (hexOpen b $ end c)

顶部的让位列表中的让我感到烦恼,但由于我没有所有的代码,我真的不知道如何以其他方式做到这一点。如果你可以更深入地修改,我建议你使用更多的组合器(map,foldr,foldl'等),因为它们确实减少了我的经验中的代码大小。

注意,代码未经过测试,可能无法编译。