如果我有类似的东西:
func (x1:x2:x3:xs) = xs
那么x1,x2,x3
必须存在,是吗?
他们不能[]
,但必须(再次,必须)有一个价值,是吗?
另外,xs
可以是[]
或[a]
或[a,a,a]
(等等),是吗?
(在[a]
中我的意思是它是一个带有一个数字的列表,[a,a,a]
是三个数字的列表。
我也有定义isPrefixOf的函数:
myIsPrefixOf :: (Eq a) => [a] -> [a] -> Bool
[] `myIsPrefixOf` [] = True
[] `myIsPrefixOf` (x:xs) = True
list `myIsPrefixOf` [] = False
(l:ls) `myIsPrefixOf` (x:xs) = if l == x then ls `myIsPrefixOf` xs
else False
如果我删除第一个模式,该函数将如下所示:
myIsPrefixOf :: (Eq a) => [a] -> [a] -> Bool
[] `myIsPrefixOf` (x:xs) = True
list `myIsPrefixOf` [] = False
(l:ls) `myIsPrefixOf` (x:xs) = if l == x then ls `myIsPrefixOf` xs
else False
现在我要写:
[] `myIsPrefixOf` []
我会得到:假(它应该是真的)
是因为第一个模式在他的右侧元素中有(x:xs)
,因此,x
必须带有一个值,因此我通过第一个模式,然后进入第二个模式:
list `myIsPrefixOf` [] = False
匹配,并返回False 我是对的吗?
如果我是对的,那么区别在于如果我写(x:xs)
,x
必须是一个值而不是[]
。
另一方面,如果我写list
,它可以匹配[]
和[a]
以及[a,a,a]
(等等),因此,{{1}第二个模式,将匹配我输入中的第一个list
,因此我会得到假?
(和以前一样,[]
我的意思是它是一个带有一个数字的列表,而[a]
是三个数字的列表)。
另外,为了纠正这种情况,我需要更换:
[a,a,a]
:
[] myIsPrefixOf
(x:xs) = True
现在是表达式:
myIsPrefixOf
将再次匹配:
[] `myIsPrefixOf` list = True
希望我对这些事情是正确的,现在又提出另一个问题:
这是从一开始的固定功能(应用更改后)
[] `myIsPrefixOf` []
[] `myIsPrefixOf` [1,2,3]
现在,如果我删除了第二个模式匹配,那么该函数将如下所示:
[] `myIsPrefixOf` list = True
并调用函数:
myIsPrefixOf :: (Eq a) => [a] -> [a] -> Bool
[] `myIsPrefixOf` list = True
list `myIsPrefixOf` [] = False
(l:ls) `myIsPrefixOf` (x:xs) = if l == x then ls `myIsPrefixOf` xs
else False
我得到一个错误,表示该功能没有详尽的模式 我想看看我是否理解为什么会这样 该函数通过第一个模式并进入第二个模式:
myIsPrefixOf :: (Eq a) => [a] -> [a] -> Bool
[] `myIsPrefixOf` list = True
(l:ls) `myIsPrefixOf` (x:xs) = if l == x then ls `myIsPrefixOf` xs
else False
这样:
[1,2] `myIsPrefixOf` [1]
和:
(l:ls) `myIsPrefixOf` (x:xs) = if l == x then ls `myIsPrefixOf` xs
else False
。
他们都是[1,2] `myIsPrefixOf` [1]
,所以我再次匹配第二种模式:
l == x
现在,1
,但是(2:[]) `myIsPrefixOf` ([]:[])
因此,表达式l == 2
返回无穷尽的模式......
是因为我试图检查数字和列表之间的相等性吗?
等参数(==)应该只检查相同类型的元素?
(即:x == []
或l == x
)
答案 0 :(得分:4)
对于学习Haskell的人来说,这似乎是一种常见的误解。 :
构造不是列表连接。因此,x:xs
不匹配“名为x
的事物列表,后跟名为xs
的事物列表”。相反,请将:
视为名为StartsAListThatContinues
。
同样,[]
构造并不意味着“我不关心”或“某些列表,无论如何”。可以把它想象成NoMore
。
现在,想象一下您的原始代码是:
myIsPrefixOf :: (Eq a) => [a] -> [a] -> Bool
NoMore `myIsPrefixOf` NoMore = True
NoMore `myIsPrefixOf` (x `StartsAListThatContinues` xs) = True
list `myIsPrefixOf` NoMore = False
(l `StartsAListThatContinues` ls) `myIsPrefixOf` (x `StartsAListThatContinues` xs) = if l == x then ls `myIsPrefixOf` xs
最后,要意识到列表可以是NoMore
或StartsAListThatContinues
结构。一个或另一个,就是这样。
在这些条件下,也许很清楚你的代码是如何减少的(记住_
意味着“我不关心”):
myIsPrefixOf :: (Eq a) => [a] -> [a] -> Bool
NoMore `myIsPrefixOf` _ = True
list `myIsPrefixOf` NoMore = False
(l `StartsAListThatContinues` ls) `myIsPrefixOf` (x `StartsAListThatContinues` xs) = if l == x then ls `myIsPrefixOf` xs
然后
myIsPrefixOf :: (Eq a) => [a] -> [a] -> Bool
NoMore `myIsPrefixOf` _ = True
_ `myIsPrefixOf` NoMore = False
(l `StartsAListThatContinues` ls) `myIsPrefixOf` (x `StartsAListThatContinues` xs) = if l == x then ls `myIsPrefixOf` xs
答案 1 :(得分:4)
您对第一个问题的理解是正确的,但您对第二个问题的理解不是。
要了解原因,请从实际功能中退一步并查看列表。列表有两个构造函数[]
和:
。因此,完整的模式匹配需要涵盖两种情况。
您的函数有两个列表参数,因此您需要涵盖2 * 2 == 4
个案例。这将始终是一个带有两个列表参数的函数的情况;如果你保留一个组合,你会得到一些输入的“非详尽模式”错误。这些是您在第一个版本中的案例:
[] `f` [] = True
[] `f` (x:xs) = True
(l:ls) `f` [] = False
(l:ls) `f` (x:xs) = ...
当您在两个列表构造函数上避免模式匹配时,可以将两个案例折叠为一个。这就是你在第一个问题中所做的:
[] `f` list = True
...
这里忽略了第二个参数的细节 - 它与哪个列表构造函数无关。只要这两种情况的答案相同,就像这样就可以将它折叠起来,就像这种情况一样。
对于你的第二个问题,你想放弃第三个案例。避免“非详尽模式”错误的唯一方法是使第四种情况不那么具体:
(l:ls) `f` xlist = ...
但是你被卡住了,因为你不能再找到xlist
的第一个元素了,因为你不知道它不是空的。您可以执行head xlist
,但这会在空列表中崩溃。所以实际上你必须首先检查空列表:
(l:ls) `f` xlist = if null xlist then False
else if l == head xlist then ls `myIsPrefixOf` tail xlist
else False
但是那种冗长的原始模式匹配更好。
您在第二个问题中出错的具体方法是手动执行isPrefixOf [1,2] [1]
。
该函数通过第一个模式并进入第二个模式:
(l:ls) `myIsPrefixOf` (x:xs) = if l == x then ls `myIsPrefixOf` xs else False
这样:
[1,2] `myIsPrefixOf` [1]
和
l == x.
到目前为止很好。
他们都是1,所以我再次匹配第二种模式:
等一下,等一下,弄清楚这里的所有值。我们已经知道l==x==1
。但也ls==[2]
和xs==[]
。
现在,当我们重复时,ls
将不匹配第一个模式(它不是空的),但xs
将与第二个模式不匹配(它是空的,(x:xs)
需要一个:
对象,而不是[]
)。因此,该功能以“非详尽模式”崩溃。
答案 2 :(得分:1)
您的理解大多是正确的,但您似乎确实遇到了一些问题。如果您有一个列表list
,表示您与x:xs
匹配,那么list
和xs
都是列表类型,但x
是列表的元素类型。因此x
除非您有列表列表,否则[]
不能等于[1,2] `myIsPrefixOf` [1]
。
所以,在你的第二个例子中,在通话中
1
匹配[2] `myIsPrefixOf` []
后的递归调用是
[]:[]
(也就是说,右侧不是[[]]
,它与{{1}}相同,一个元素列表,其中唯一的元素是空列表)并且您没有与第一个参数匹配的模式非空,第二个参数为空。