如何检查两个列表是否部分相同haskell

时间:2014-10-19 22:59:31

标签: function haskell functional-programming

这是我的代码我试图检查列表是否可以在另一个列表中相同。这是一个多米诺骨牌游戏Domino=(Int,Int)Board = [Domino]以及左右两端。我要检查是否有任何多米诺骨牌进入董事会说例如,多米诺(2,3)进入董事会[(3,4)(5,6)]应该能够到达左端,因为(2,3)和{{1有一个类似的元素。这是我的代码

(3,4)

1 个答案:

答案 0 :(得分:1)

您为电路板使用的模式匹配不完整。 [(h1,t1)]模式匹配具有一个元素(一对(h1,t1))的电路板。

这与使用模式(h1,t1):[]相同,即。包含元素:后跟空列表(h1,t1)的列表([])。

如果我们尝试使用您提供的示例运行代码,(2,3)[(3,4), (5,6)](注意:列表元素之间需要逗号!)我们将获得以下内容:

goesP (2,3) [(3,4), (5,6)] LeftEnd

Haskell将尝试将这些参数与您定义中的模式从上到下进行匹配。

它将首先检查以下模式:

goesP (h,t) [(h1,t1)] LeftEnd

第一个和第三个参数将匹配,通过统一' h 2t 3LeftEnd LeftEnd,但第二个将无法匹配。论证[(3,4), (5,6)]是'句法糖'对于列表(3,4):(5,6):[],模式[(h1,t1)]是列表(h1,t1):[]的语法糖。我们可以将h13t14统一起来,但没有任何内容可以统一(5,6)

Haskell将继续下一个可能性:

goesP (h,t) [(h1,t1)] RightEnd

第一个参数将匹配(h2t3),但第二个参数将失败,原因与前一个子句相同。第三个参数也将无法匹配,因为LeftEndRightEnd是不同的值(但这是重点;))。

然后,Haskell将看到没有更多的可能性,因此程序将崩溃。

要解决此问题,您需要更改第二个参数的模式,以便正确处理具有多个Domino的Boards。

LeftEnd的情况非常简单,只需将一个元素(h1,t1):[]的列表更改为至少一个元素列表(h1,t1):_(我也是在=之后添加了额外的otherwise

goesP (h,t) ((h1,t1):_) LeftEnd
      | h==h1 || t==h1 = True
      | otherwise      = False

RightEnd的情况更难,因为我们想要与列表的 last 元素进行比较,但我们只能访问第一个。在这种情况下,我们可以保留用于检查单元素列表的定义,但添加另一个使用递归的定义:如果列表包含多个元素,则删除第一个元素并再次检查。这样,任何非空列表最终都会被分解,直到它只有一个元素,您现有的模式可以使用(再次,我添加了一个缺失的=):

goesP (h,t) [(h1,t1)] RightEnd
      | h==h1 || t==h1 = True 
      | otherwise      = False

goesP (h, t) (_:xs)   RightEnd = goesP (h, t) xs RightEnd

现在,Haskell将[(3,4), (5,6)](3,4):(5,6):[]的糖)与(h1,t1):[]匹配。这将失败,因为列表具有不同的长度。然后,它会[(3,4), (5,6)]_:xs匹配,这将成功,将xs(5,6):[]统一起来。然后,我们使用xs再次运行该函数。这次(5:6):[] (h1,t1):[]统一,因此我们可以检查数字是否相等。

另外,观察:goesP实际上过于复杂。您正在使用"模式警卫"在值True和值False之间进行选择;但是,模式保护也需要 Bool才能使用。换句话说,像这样的代码:

| h==h1 || t==h1 = True
| otherwise      = False

可以读作"创建Boolh==h1 || t==h1;如果是True,则返回True。如果是False,则返回False。"

显然这是多余的:我们只能返回值h==h1 || t==h1

goesP (h,t) ((h1,t1):_) LeftEnd  = h==h1 || t==h1
goesP (h,t) [(h1,t1)]   RightEnd = h==h1 || t==h1
goesP (h, t) (_:xs)     RightEnd = goesP (h, t) xs RightEnd

更新:修正了我的RightEnd代码