繁体   English   中英

简化一些Haskell代码

[英]Simplifying some Haskell code

所以我正在为类似跳棋的游戏开发一个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函数提供示例类型签名。

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

为什么? 我已经写了几次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)

结果,加上其他各种事情。

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

不要滥用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'等),因为它们确实减少了我的经验中的代码大小。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM