Haskell - 家庭作业 - 连接两个列表

时间:2011-05-27 16:03:51

标签: list haskell recursion

我获得了一个Char数组,必须将其翻译为Moves(如下所示)

data Move = N | S | W | E | X
newtype Moves = Moves [Move]

createMoves:: [Char]-> Moves
createMoves (x:xs) =  if xs==[] then Moves [createMove(x)]
                      else Moves [createMove (x)] 

createMove:: Char-> Move
createMove (x) = if x=='N' then N
                 else if x=='S' then S
                 else if x=='W' then W
                 else if x=='E' then                      
                 else X

但是,我只是成功获得了列表的第一项。我已经尝试了许多方法来使createMoves递归,但我无法做到正确。你能指导我吗?

5 个答案:

答案 0 :(得分:3)

if语句的分支是相同的,因此它什么都不做。

编程递归函数时,有两种情况。 基本的,您应该声明createMoves [] = []。 递归有点复杂;基本上,对于每个x,您创建一个移动,该移动是附加到使用xs上的递归调用构建的列表的第一个元素。

更简单的方法是使用map函数。您还可以查看其实现。 顺便说一句,对于createMove,您可以使用模式匹配而不是许多if s。

答案 1 :(得分:2)

您的问题似乎集中在将xs上的递归调用结果与createMove x的结果相结合。所以,让我们来介绍一个将要处理的辅助函数!

createMoves:: [Char]-> Moves
createMoves (x:xs) =  if xs==[] then Moves [createMove x]
                      else createHelper (createMove x) (createMoves xs)

现在,createHelper的类型应该是什么?它的第一个参数是Move,第二个参数是Moves,它应该将第一个参数放在第二个包含的Move列表前面,然后'重新包装'它值为Moves的值。要获得Move的列表,您需要使用模式匹配,如下所示:

createHelper :: Move -> Moves -> Moves
createHelper m (Moves ms) = Moves (m:ms)

这应该可以解决问题,但是Moves构造函数上的所有这些匹配然后重新应用它有点愚蠢,并且可能效率低下。更好的方法是将[Char]逐个转换为[Move],并且仅在最后添加Moves构造函数。这导致了类似的东西(仍然符合你原来的想法):

createMoves :: [Char] -> Moves
createMoves cs = Moves (createMoveList cs)

createMoveList :: [Char] -> [Move]
createMoveList (x:xs) = if xs == [] then [] else createMove x : createMoveList xs

createMoveList是一种在Haskell中经常出现的模式,即将一个函数(在本例中为createMove)应用于列表中的每个元素。这是map函数的本质(如果你还没有,我相信你很快就会在课程中得到它!)。

如果您使用它,您还可以摆脱createMoves给出空列表时失败的问题。所以我要采用的解决方案是:

createMoves :: [Char] -> Moves
createMoves cs = Moves (map createMove cs)

createMoves = Moves . map createMove

但那是另一个故事!

答案 2 :(得分:1)

您的createMoves函数仅对其给出的列表中的一个元素进行操作。

尝试使用map功能。换句话说,使用以下命令启动您的功能:

createMoves list = Moves (map 

[...]

答案 3 :(得分:1)

您可能希望使用警卫(即|)代替ifthenelse

答案 4 :(得分:0)

首先,您应该删除newtype声明;如果您希望打印列表,只需让Move类型派生Show

接下来,您可以使用createMoves删除map函数中的显式递归。为了将来参考,您可以在Hoogle上按名称和类型签名查找功能。

最后,您可以使用模式匹配来消除针对常量的所有相等性测试。使用Move类型的不相关示例是

isN :: Move -> Bool
isN N = True
isN _ = False

请注意,_字符表示“忽略此值”。如果你尚未涉及模式匹配,那么守卫可能仍然比嵌套if更好。