我获得了一个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递归,但我无法做到正确。你能指导我吗?
答案 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)
您可能希望使用警卫(即|
)代替if
,then
和else
。
答案 4 :(得分:0)
首先,您应该删除newtype
声明;如果您希望打印列表,只需让Move
类型派生Show
。
接下来,您可以使用createMoves
删除map
函数中的显式递归。为了将来参考,您可以在Hoogle上按名称和类型签名查找功能。
最后,您可以使用模式匹配来消除针对常量的所有相等性测试。使用Move
类型的不相关示例是
isN :: Move -> Bool
isN N = True
isN _ = False
请注意,_
字符表示“忽略此值”。如果你尚未涉及模式匹配,那么守卫可能仍然比嵌套if
更好。