2

如果我有这样的事情:

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,它可以匹配[]and [a]and [a,a,a](etc'),因此,list第二个模式将匹配 []我输入中的第一个,因此我会得到 False?
(和以前一样,[a]我的意思是它是一个带有一个数字的列表,并且[a,a,a]是三个数字的列表)。

另外,为了纠正这种情况,我需要更换:

[]     myIsPrefixOf  (x:xs)  = True
接着就,随即:

[]     `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返回不详尽的模式...
是因为我试图检查数字和列表之间的相等性吗?
相等参数(==)应该只检查相同类型的元素吗?
(即:'a' == 'b'1 == 3

好吧,我明白了吗?:-)
非常感谢:-)。

4

3 回答 3

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

最后,意识到一个列表可以是NoMoreStartsAListThatContinues结构。一个或另一个,仅此而已。

在这些情况下,也许很清楚如何减少您的代码(记住这_意味着“我不在乎”):

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
于 2010-01-20T14:41:44.813 回答
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)需要一个:对象,而不是[])。因此,该函数以“非详尽模式”崩溃。

于 2010-01-20T15:29:45.203 回答
1

您的理解大多是正确的,但您似乎确实有一些问题。当你有一个列表,比如说list,你正在与 匹配x:xs,那么两者listxs都是列表类型,但是x是列表的元素类型。因此,除非您有这些示例所没有的列表列表,否则不可能x等于。[]

所以,在你的第二个例子中,在电话中

[1,2] `myIsPrefixOf` [1]

匹配1s 后的递归调用是

[2] `myIsPrefixOf` []

(也就是说,右侧 not []:[],这将与 相同[[]],一个元素列表,其唯一元素是空列表)并且您没有与第一个参数非空匹配的模式并且第二个是空的。

于 2010-01-20T14:01:17.170 回答