这是我的代码我试图检查列表是否可以在另一个列表中相同。这是一个多米诺骨牌游戏Domino=(Int,Int)
和Board = [Domino]
以及左右两端。我要检查是否有任何多米诺骨牌进入董事会说例如,多米诺(2,3)
进入董事会[(3,4)(5,6)]
应该能够到达左端,因为(2,3)
和{{1有一个类似的元素。这是我的代码
(3,4)
答案 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
2
,t
3
和LeftEnd
LeftEnd
,但第二个将无法匹配。论证[(3,4), (5,6)]
是'句法糖'对于列表(3,4):(5,6):[]
,模式[(h1,t1)]
是列表(h1,t1):[]
的语法糖。我们可以将h1
与3
和t1
与4
统一起来,但没有任何内容可以统一(5,6)
。
Haskell将继续下一个可能性:
goesP (h,t) [(h1,t1)] RightEnd
第一个参数将匹配(h
为2
,t
为3
),但第二个参数将失败,原因与前一个子句相同。第三个参数也将无法匹配,因为LeftEnd
和RightEnd
是不同的值(但这是重点;))。
要解决此问题,您需要更改第二个参数的模式,以便正确处理具有多个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
可以读作"创建Bool
值h==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代码