Haskell-递归调用元组列表

时间:2014-08-11 16:14:19

标签: haskell recursion tuples

我正在处理以下代码。如果条件checkerAlive为True,我试图以递归方式调用列表[(Int,Int)]中的下一个元素。我不知道如何进行递归调用。

    makemoves :: (Int,[Char],[[Char]],[(Int,Int)]) -> (Int,[Char],[[Char]])


    makemoves (time, captures, board, [(moveFrom, moveTo)] ) 
        |checkerAlive ( board) == True = onemove (time,captures,board,(moveFrom,moveTo))
        |otherwise = reset (time, captures, board)

1 个答案:

答案 0 :(得分:3)

[(Int, Int)]参数有moves,而您正在执行的匹配是[(moveFrom, moveTo)],但匹配单个元素列表,仅此而已。你可能想要的更像是

makemoves (time, captures, board, (moveFrom, moveTo):moves)

然后你可以在moves上进行递归调用,虽然我不知道你希望在没有更多代码的情况下放置递归的位置。


如果你将游戏中的游戏状态从两个参数中分离出来,可能会让这更容易:

makemoves :: (Int, String, [String]) -> [(Int, Int)] -> (Int, String, [String])
makemoves gameState [] = gameState
makemoves (time, captures, board) ((moveFrom, moveTo):moves)
    | checkerAlive board = makemoves (onemove (time, captures, board, (moveFrom, moveTo))) moves
    | otherwise          = reset (time, captures, board)

请注意,这只是猜测你想用这个功能做什么,我不知道你真正想做什么。我还添加了移动列表为空的情况,并将checkerAlive (board) == True更改为简单checkerAlive board,因为检查布尔值是否True总是给你布尔值,它是多余的。您可能希望使用onemove进行相同的更改,以便它接受两个参数:

onemove :: (Int, String, [String]) -> (Int, Int) -> (Int, String, [String])
onemove (time, captures, board) (moveFrom, moveTo) = ...

此时,您可能值得花时间为游戏状态引入至少一个类型别名:

type GameState = (Int, String, [String])

一个人搬家

type Move = (Int, Int)

然后你可以把你的功能写成

makemoves :: GameState -> [Move] -> GameState
makemoves gameState [] = gameState
makemoves gameState@(_, _, board) (move:moves)
    | checkerAlive board = makemoves (onemove gameState move) moves
    | otherwise          = reset gameState

onemove :: GameState -> Move -> GameState
onemove (time, captures, board) (moveFrom, moveTo) = ...

有了这样的因素,希望你更容易看到你的应用程序逻辑实际上是如何放在一起的,以及你不需要像对待另一个列表那样区别地处理你的元组列表(移动)。在makemoves中,您甚至可以忽略这样一个事实,即它们甚至是元组并将其直接传递给onemove,而rotatePoint :: (Double, Double) -> Double -> (Double, Double) rotatePoint (x, y) angle = ... 非常关注。此外,我试图展示如何将元组拆分为多个参数可以清理代码并使其更易于使用。一个好的经验法则是考虑不同的参数是否具有固有的相关性,或者它们是否有意义地分开。如果它们本质上是相关的,那么将它们组合在一起,否则将它们分开。例如,我可能会创建一个函数

x

将一个点围绕原点旋转给定角度。值y(x, y, angle)在这里具有固有的相关性,在谈论平面中的变换点时它们没有意义分离。另一方面,传递给此函数angle是没有意义的,因为(x, y)实际上与点(Int, [Char], [[Char]])没有任何关系。另一个好用的指标是你是否从一个函数返回一个元组作为相同的类型,所以你在这里返回{{1}},所以在整个你的元组中保留这些值可能是个好主意。代码,而不是向该元组添加任何元素。