2014-09-06 23 views
3

我是Haskell的新手,我正在尝试学习基础知识。我需要声明一个名为Pos的类型,这个类型将有两个整数,然后我需要指定North,South,West,East的方向,以便根据方向改变位置。 一旦我这样做了,我需要制作一个叫做移动的函数,这个函数将取得一系列移动和初始位置,并在所有移动之后返回位置。 这是我的代码,但我坚持要点迭代通过移动列表。基本的Haskell函数

type Pos = (Int, Int) 
data Direction = North | South | East | West 

move :: Direction -> Pos -> Pos 
move North (x,y) = (x, y+1) 
move West (x,y) = (x-1, y) 
move South (x,y) = (x, y-1) 
move East (x,y) = (x+1, y) 

moves :: [Direction] -> Pos -> Pos 
moves [] (x,y) = (x,y) 
moves (h:xs) (x,y) 
     | h == North = move North (x,y) 
     | h == West = move West (x,y) 
     | h == South = move South (x,y) 
     | otherwise = move East (x,y) 

我在这里错过了什么?

+3

你不*有*要“迭代”。 *递归地考虑*。你有一个起点'p'和一个序列'm1,...,mn'。要执行这些动作,首先在起点'p'执行移动'm1',从而到达'p''点。现在,您必须执行移动'm2,...,mn',其起点为'p'' ...这与之前的问题相同,但参数不同。 – Bakuriu 2014-09-06 09:13:08

回答

3

之前或对应h单招后,你需要做一个递归调用movesDirection S的其余部分。如果说之前,那么每一种情况下变成类似:

move North (moves xs (x,y)) 

,如果你希望它是后,这可能是考虑到问题的规范正确的方法,那么这将是:

moves xs (move North (x,y)) 

但是重复moves的案例分析有点不必要,因为您可以直接拨打moveh,例如

moves (h:xs) (x,y) = moves xs (move h (x,y)) 

事实上,你甚至都不需要对(x,y)元组明确模式匹配;

moves (h:xs) pos = moves xs (move h pos) 

作为另一个答案指出,这是一样的内置功能foldl(高达参数命令),但它可能是最好的了解如何通过先用手做。

+0

我认为如果使用'moves(h:xs)(x,y)=移动xs(移动h(x,y))',它会变得更加清晰。 – chamini2 2014-09-06 09:21:12

+0

谢谢。我以为我不得不使用监护人来检查列表中的移动方式...... – sokras 2014-09-06 09:30:19

9

将一系列事物组合成一件事叫做折叠列表。有(大约)两个列表折叠:foldlfoldr。倾向于使用折叠是学习Haskell的重要一步。我们需要foldl,其类型为

foldl :: (a -> b -> a) -> a -> [b] -> a 

现在foldl作品通过组合功能和初始值的东西,在列表中结合,因此,例如

foldl (£) s [x,y,z] = (((s £ x) £ y) £ z) 

(在foldll是所以它的存在帮助你记住你的起始值s将在左边结束,但更重要的是括号与左边相关联。)

第三个参数是列表参数[b]。我们将使用它作为移动列表,因此类型b将为Direction

第二个参数是类型为a的起始值,因此我们将使用它作为初始位置,因此输入a将是Pos

第一个参数是一个将列表中的某些内容与当前值组合的函数。现在我们知道类型baDirectionPos我们知道我们的组合函数必须具有类型Pos -> Direction -> Pos。移动函数几乎正是我们需要的,除了我们需要交换参数。 flip函数就是这样,所以flip move有我们需要的类型。

所以我们专门的foldl类型为

foldl :: (Pos -> Direction -> Pos) -> Pos -> [Direction] -> Pos 

,并定义

moves :: [Direction] -> Pos -> Pos 
moves ds i = foldl (flip move) i ds 

现在foldl有着 “严格” 的版本,称为foldl'在这种情况下更快,所以如果你在快节奏的游戏中使用它,或者正在处理大量的动作,你会想要使用它。

与往常一样,您可以通过在hoogle上搜索其名称或类型来查找功能。

还有一个折叠函数,它以不同的方式折叠列表。您可以在this question中了解它们之间的区别。总之,虽然foldr是这样的:

foldr (?) s [x,y,z] = (x ? (y ? (z ? s))) 

(在foldrr是短期的权利,所以它的存在,以帮助你记住,你的起始值s最终会在正确的,但更重要的是,括号与右边相关联。)

+0

如果列表中的第一步是首先采取的行动,难道你不想要一个foldl吗? – 2014-09-06 15:00:53

+0

@ReinHenrichs呵呵 - 我刚刚登录,因为当我的孩子们玩时,我达到了同样的想法。正在编辑中。 – AndrewC 2014-09-06 15:02:58

+0

@ReinHenrichs谢谢。排序。 – AndrewC 2014-09-06 15:17:59