Haskell——列表上的递归调用
我有一个函数Haskell——列表上的递归调用,haskell,recursion,Haskell,Recursion,我有一个函数onemove,我正在递归调用一个列表moves。函数onemove返回一个三元组(Int、[Char]、[Char]]),即time、捕获和板。我想为moves列表中的每个移动调用输入元组上的函数onemove。以下是我迄今为止提供的代码: makemoves :: (Int,[Char],[[Char]],[(Int,Int)]) -> (Int,[Char],[[Char]]) makemoves (time, captures, board, [] )
onemove
,我正在递归调用一个列表moves
。函数onemove
返回一个三元组(Int、[Char]、[Char]])
,即time
、捕获
和板
。我想为moves
列表中的每个移动调用输入元组上的函数onemove
。以下是我迄今为止提供的代码:
makemoves :: (Int,[Char],[[Char]],[(Int,Int)]) -> (Int,[Char],[[Char]])
makemoves (time, captures, board, [] ) = (time, captures, board)
makemoves (time, captures, board, (moveFrom, moveTo):moves )
| checkerAlive board = makemoves (onemove (time, captures, board, move:moves))
| otherwise = resetGame (time, captures, board)
where copyTime = time
copyCaptures = captures
copyBoard = board
move = (moveFrom,moveTo)
tempTuple = onemoving (time, captures, board, move)
如何递归调用函数makemoves
onemove
返回一个3元组,而makemoves需要一个4元组,即返回的3元组加上下一个move。谢谢
OneMoves返回一个3元组,而makemoves需要一个4元组,
这是返回的3元组加上下一步。谢谢
不,它需要一个剩余移动的列表,您已经在移动中找到了该列表
记得前几天,我告诉过你让函数接受多个参数,而不是一个元组中的所有参数吗?这就是原因。您现在应该这样做:
makemoves :: [(Int,Int)] -> (Int,[Char],[[Char]]) -> (Int,[Char],[[Char]])
makemoves [] (time, captures, board) = (time, captures, board)
makemoves (move:moves) (time, captures, board)
| checkerAlive board = makemoves moves (onemove (time, captures, board, move:moves))
| otherwise = resetGame (time, captures, board)
我不确定所有这些where条款都是用来做什么的;它们都没有被使用
编辑:实际上,忽略以下内容,因为您需要基于checkerAlive
函数的提前退出逻辑。它仍然可以写成折页,但在这一点上可能比它的价值更大
另外,您在这里写的是函数式编程中非常常见的递归模式,称为“fold”。这整件事可以改写为:
makemoves :: [(Int,Int)] -> (Int,[Char],[[Char]]) -> (Int,[Char],[[Char]])
makemoves moves env = foldr onemoveOrReset env moves
onemoveOrReset :: (Int,Int) -> (Int,[Char],[[Char]]) -> (Int,[Char],[[Char]])
OneMoves返回一个3元组,而makemoves需要一个4元组,
这是返回的3元组加上下一步。谢谢
不,它需要一个剩余移动的列表,您已经在移动中找到了该列表
记得前几天,我告诉过你让函数接受多个参数,而不是一个元组中的所有参数吗?这就是原因。您现在应该这样做:
makemoves :: [(Int,Int)] -> (Int,[Char],[[Char]]) -> (Int,[Char],[[Char]])
makemoves [] (time, captures, board) = (time, captures, board)
makemoves (move:moves) (time, captures, board)
| checkerAlive board = makemoves moves (onemove (time, captures, board, move:moves))
| otherwise = resetGame (time, captures, board)
我不确定所有这些where条款都是用来做什么的;它们都没有被使用
编辑:实际上,忽略以下内容,因为您需要基于checkerAlive
函数的提前退出逻辑。它仍然可以写成折页,但在这一点上可能比它的价值更大
另外,您在这里写的是函数式编程中非常常见的递归模式,称为“fold”。这整件事可以改写为:
makemoves :: [(Int,Int)] -> (Int,[Char],[[Char]]) -> (Int,[Char],[[Char]])
makemoves moves env = foldr onemoveOrReset env moves
onemoveOrReset :: (Int,Int) -> (Int,[Char],[[Char]]) -> (Int,[Char],[[Char]])
线条像
copyTime = time
在Haskell中完全是多余的:复制任何东西都没有意义。只有值,没有可能在某一点上改变的“对象”,并且值可以在任何地方使用。因此,您的整个where
块是无用的
为了解决你的问题,让我们考虑一个更简单的例子:不是移动,而是试图添加的简单数字。用元组编写(不过,正如Mark Whitfield所说,curried函数更好!)
好,现在是递归情况。目前,在您的代码中,基本上
makeAdds (num, inc:incs) = makeAdds (addOne (num, inc:incs))
这是错误的,原因有二:
addOne
无法使用列表,但您正在处理它inc:incs
——您刚刚从输入中获得的列表。显然,您只想使用head元素,即单独使用inc
makeAdds
需要两个参数,第二个是列表。很明显,这是剩下的名单了
makeAdds(num,inc:incs)=makeAdds(addOne(num,inc),incs)
很简单
也就是说,所有这些的“正确”版本当然是
addOne :: Int -> Int -> Int
addOne = (+) -- Yeah, you can do that.
makeAdds :: [Int] -> Int -> Int -- Observe I've switched the order:
-- "state" arguments best come last, useful with partial application
makeAdds [] = id
makeAdds (inc:incs) = makeAdds incs . addOne inc
线条像
copyTime = time
在Haskell中完全是多余的:复制任何东西都没有意义。只有值,没有可能在某一点上改变的“对象”,并且值可以在任何地方使用。因此,您的整个where
块是无用的
为了解决你的问题,让我们考虑一个更简单的例子:不是移动,而是试图添加的简单数字。用元组编写(不过,正如Mark Whitfield所说,curried函数更好!)
好,现在是递归情况。目前,在您的代码中,基本上
makeAdds (num, inc:incs) = makeAdds (addOne (num, inc:incs))
这是错误的,原因有二:
addOne
无法使用列表,但您正在处理它inc:incs
——您刚刚从输入中获得的列表。显然,您只想使用head元素,即单独使用inc
makeAdds
需要两个参数,第二个是列表。很明显,这是剩下的名单了
makeAdds(num,inc:incs)=makeAdds(addOne(num,inc),incs)
很简单
也就是说,所有这些的“正确”版本当然是
addOne :: Int -> Int -> Int
addOne = (+) -- Yeah, you can do that.
makeAdds :: [Int] -> Int -> Int -- Observe I've switched the order:
-- "state" arguments best come last, useful with partial application
makeAdds [] = id
makeAdds (inc:incs) = makeAdds incs . addOne inc
所以我想出来了,这是解决办法
makemoves (time, captures, board, (moveFrom, moveTo):moves )
| checkerAlive board = makemoves (newTime,newCaptures,newBoard,moves)
| otherwise = resetGame (time, captures, board)
where move = (moveFrom,moveTo)
(newTime,newCaptures,newBoard) = onemoving (time, captures, board, move)
您必须首先为第一步创建一个临时保持器,因此(newTime,newCaptures,newBoard)
,然后通过调用makemoves将临时保持器传递到移动列表中的下一步,因此我找到了解决方案
makemoves (time, captures, board, (moveFrom, moveTo):moves )
| checkerAlive board = makemoves (newTime,newCaptures,newBoard,moves)
| otherwise = resetGame (time, captures, board)
where move = (moveFrom,moveTo)
(newTime,newCaptures,newBoard) = onemoving (time, captures, board, move)
您必须首先为第一步创建临时保持架,因此(newTime,newCaptures,newBoard)
,然后通过调用makemoves
将临时保持架传递到移动列表中的下一步,如果此类型检查,为什么onemove
的类型签名与makemoves
的类型签名相同?我从您的代码中没有得到一些东西。例如,为什么您有一个copyBoard=board
?也可以使用@
模式,而不是在where
子句中定义move
:move@(moveFrom,moveTo):moves
。关于您的问题,在某些情况下,编写一个返回冗余信息的helper函数,并通过调用它并删除不需要的信息来编写实际函数更容易。懒散也会避免实际计算不需要的信息。如果这种类型检查,为什么onemove
的类型签名与makemoves
相同?我没有从您的代码中得到一些东西。例如,你为什么有