简化一些Haskell代码

简化一些Haskell代码,haskell,monads,Haskell,Monads,所以我正在为一个类似跳棋的游戏开发一个minimax实现,以帮助自己更好地学习Haskell。我遇到问题的函数获取游戏状态列表,并生成直接后续游戏状态列表。就像跳棋一样,如果可以跳,玩家必须跳。如果有多个,玩家可以选择 在大多数情况下,这与列表monad配合得很好:循环所有输入游戏状态,循环所有可以跳转的弹珠,循环该弹珠的所有跳转。这个列表单子很好地将所有列表平铺成一个简单的状态列表 诀窍是,如果给定的游戏状态没有跳转,我需要返回当前的游戏状态,而不是空列表。下面的代码是我想出的最好的方法,但对

所以我正在为一个类似跳棋的游戏开发一个minimax实现,以帮助自己更好地学习Haskell。我遇到问题的函数获取游戏状态列表,并生成直接后续游戏状态列表。就像跳棋一样,如果可以跳,玩家必须跳。如果有多个,玩家可以选择

在大多数情况下,这与列表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 []
eHex::Coord->Coord——将坐标立即返回到棋盘的东方
nwHex::Coord->Coord--将坐标立即返回到板上的西北方向
generateJumpsIter::[ZertzState]->[ZertzState]
generateJumpsIter states=do
返回
n@_->n
哪里
儿童ws@(ZertzState s1 s2 b p)=do
(c,颜色)返回$ZertzState s1(颜色)
(开始c)c(结束c)b)p
其他[]

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

不要滥用列表的monads符号,它太重了。此外,您还可以以相同的方式使用列表理解:

do x <- [1..3]
   y <- [2..5]      <=>  [ x + y | x <- [1..3], y <- [2..5] ]
   return x + y
dox
诀窍是,如果给定的游戏状态没有跳转,我需要返回当前的游戏状态,而不是空列表

为什么??我已经写过几次极小极大,我无法想象这样一个函数的用途。使用类型函数不是更好吗

nextStates :: [ZertzState] -> [Maybe [ZertzState]]
[ZertzState] -> [(ZertzState, [ZertzState])]

但是,如果您确实希望返回“下一个状态列表,或者如果该列表为空,则返回原始状态”,那么您想要的类型是

nextStates :: [ZertzState] -> [Either ZertzState [ZertzState]]
然后你就可以很容易地把它弄平

至于如何实现,我建议定义类型为的helper函数

nextStates :: [ZertzState] -> [Maybe [ZertzState]]
[ZertzState] -> [(ZertzState, [ZertzState])]
而你却无法绘制地图

(\(start, succs) -> if null succs then Left start else Right succs)
结果,再加上其他各种事情


正如Fred Brooks所说(意译),一旦你得到了正确的类型,代码实际上是自己写的。

第一个列表理解不能是[if null(children ws),那么ws else children ws | ws listohex将具有类型listohex::[Coord->Coord]板上的每个十六进制都由一个坐标标识(这只是一对Int的同义词)。例如,函数nwHex返回输入十六进制西北方向的十六进制坐标。listOfHex然后包含这些函数对,用于确定是否可以跳转。listOfHex::[(Coord->Coord,Coord->Coord)],这是一个成对的列表,每个都是一个函数。这只是生成一组可能移动的代码的一部分,这是minimax输入的一部分。特别是,这是与生成可用跳转相关的部分。规则是类似于:如果有可用跳转,则必须执行跳转。如果有多个可用跳转,玩家可以选择跳哪一个。链式跳(即跳棋中的双跳)是允许的,如果可用的规则适用,同样需要。我一直认为这是一个递归生成的状态树。我从包含初始状态的列表开始。从中,我生成最多一跳的可到达状态列表。从这些列表中,我生成最多两跳的状态列表,以此类推。我重复这个过程,直到列表停止更改。这只有在“死胡同”状态保留在列表中,而不是进入空列表时才起作用。@Restor:是Haskell!你为什么不懒洋洋地生成无限移动树呢?你需要的所有信息都在John Hughes的论文中