如果我有这样的事情:
那么 x1,x2,x3 必须存在,是吗?
它们不能是 [],但必须(再次,必须)具有值,是吗?
另外,xs 可以是 [] 或 [a] 或 [a,a,a] (等等),是吗?
(在 [a] 我的意思是它是一个有一个数字的列表,而 [a,a,a] 是三个数字的列表)。
我也有定义 isPrefixOf:
的函数
1 2 3 4 5 6
| 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 |
如果我删除第一个模式,该函数将如下所示:
1 2 3 4 5
| 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 |
现在我要写:
我会得到:假(应该是真)。
是不是因为第一个模式在他的右侧元素中有:(x:xs),正因为如此,x 必须有一个值,因此我通过第一个模式,并到达第二个模式:
1
| list `myIsPrefixOf` [] = False |
匹配,并返回 False。
我说的对吗?
如果我是对的,那么区别在于如果我写的是 (x:xs),x 必须是一个值,而不是 []。
另一方面,如果我写 list,它可以匹配 [] 和 [a] 和 [a,a,a] (etc'),因此,第二个模式的 list 将匹配我输入中的第一个 [] ,因此我会得到 False ?
(和以前一样,在 [a] 我的意思是它是一个带有一个数字的列表,而 [a,a,a] 是三个数字的列表)。
另外,为了纠正这种情况,我需要更换:
1
| [] <wyn>myIsPrefixOf</wyn> (x:xs) = True |
这样:
1
| [] `myIsPrefixOf` list = True |
现在是表达式:
1 2
| [] `myIsPrefixOf` []
[] `myIsPrefixOf` [1,2,3] |
将再次匹配:
1
| [] `myIsPrefixOf` list = True |
希望我在这些事情上是对的,现在是另一个问题:
这是从一开始的固定功能(应用更改后)
1 2 3 4 5
| 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 |
现在,如果我删除第二个模式匹配,该函数将如下所示:
1 2 3 4
| myIsPrefixOf :: (Eq a ) => [a ] -> [a ] -> Bool
[] `myIsPrefixOf` list = True
(l :ls ) `myIsPrefixOf` (x :xs ) = if l == x then ls `myIsPrefixOf` xs
else False |
并像这样调用函数:
1
| [1,2] `myIsPrefixOf` [1] |
我收到一条错误消息,指出函数中没有详尽的模式。
我想看看我是否明白为什么会这样。
该函数通过第一个模式并到达第二个模式:
1 2
| (l:ls) `myIsPrefixOf` (x:xs) = if l == x then ls `myIsPrefixOf` xs
else False |
所以:
1
| [1,2] `myIsPrefixOf` [1] |
和:
l == x。
他们都是 1,所以我再次匹配第二个模式:
1
| (2:[]) `myIsPrefixOf` ([]:[]) |
现在,l == 2,但是 x == []
正因为如此,表达式: l == x 返回非穷举模式......
是因为我正在尝试检查数字和列表之间的相等性吗?
相等参数(==)应该只检查相同类型的元素吗?
(即:'a' == 'b' 或 1 == 3)
嗯,我明白了吗? :-)
非常感谢:-)。
- Haskell 是你的第一个函数式编程语言吗?我确实喜欢 Haskell,但它使用的许多基本思想在其他更简单的语言中更容易掌握。在 Lisp 中,(list 1 2 3) 实际上是 (cons 1 (cons 2 (cons 3 nil)));在 ML 中,[1,2,3] 实际上是 1 :: 2 :: 3 :: nil; Haskell 的列表构造遵循这个函数式传统,因此 [1,2,3] 确实是 1 : 2 : 3 : []。
-
太好了,我希望你继续走上功能性启蒙之路:-)
-
非常感谢你 :-)。
你对第一个问题的理解是正确的,但是你对第二个问题的理解不是。
要了解原因,请从实际功能退一步,看看列表。列表有两个构造函数,[] 和 :。所以一个完整的模式匹配需要涵盖这两种情况。
您的函数有两个列表参数,因此您需要涵盖 2 * 2 == 4 情况。对于带有两个列表参数的函数,情况总是如此;如果您遗漏一个组合,您将收到某些输入的"非详尽模式"错误。这些是您在第一个版本中遇到的情况:
1 2 3 4
| [] `f` [] = True
[] `f` (x:xs) = True
(l:ls) `f` [] = False
(l:ls) `f` (x:xs) = ... |
当您避免在两个列表构造函数上进行模式匹配时,您可以将两种情况合并为一种。这就是您在第一个问题中所做的:
这里忽略了第二个参数的细节——不管它是哪个列表构造函数。只要两种情况的答案相同,就可以像这样折叠它,在这种情况下就是这样。
对于您的第二个问题,您想放弃第三种情况。避免"非详尽模式"错误的唯一方法是使第四种情况不那么具体:
但是你被卡住了,因为你不能再得到 xlist 的第一个元素,因为你不知道它不是空的。您可以执行 head xlist,但这会在空列表上崩溃。所以实际上你必须先检查空列表:
1 2 3
| (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].
the function pass through the first pattern and get to the second one:
1 2
| (l:ls) `myIsPrefixOf` (x:xs) = if l == x then ls `myIsPrefixOf` xs
else False |
so:
1
| [1,2] `myIsPrefixOf` [1] |
and:
到目前为止还不错。
they both 1, so i match again the second pattern:
等等,等一下,找出这里的所有值。我们已经知道 l==x==1。还有 ls==[2] 和 xs==[].
现在当我们递归时,ls 不会匹配第一个模式(它不是空的),但是 xs 不会匹配第二个模式(它是空的,并且 (x:xs) 需要一个 : 对象,不是 [])。因此,该函数因"非详尽模式"而崩溃。
对于学习 Haskell 的人来说,这似乎是一个常见的误解。 : 构造不是列表连接。因此,x:xs 不匹配"名为 x 的事物列表后跟名为 xs 的事物列表"。相反,将 : 想象成它被命名为 StartsAListThatContinues.
同样,[] 结构并不意味着"我不在乎"或"一些列表,随便什么"。把它想象成它被命名为 NoMore.
现在,想象一下你的原始代码是:
1 2 3 4 5
| 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 结构。一个或另一个,仅此而已。
在这些条件下,也许你的代码可以减少是很清楚的(记住 _ 的意思是"我不在乎"):
1 2 3 4
| 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 |
然后
1 2 3 4
| 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 |
-
谢谢你的评论 :-)。我想在所有评论之后,我理解它(希望如此):-)。
您的理解大部分是正确的,但您似乎确实有一些问题。当你有一个列表,比如说 list,你与 x:xs 匹配,那么 list 和 xs 都是列表类型,但 x 是列表的元素类型。因此,x 不可能等于 [],除非您有一个列表列表,而这些示例没有。
所以,在你的第二个例子中,在调用
1
| [1,2] `myIsPrefixOf` [1] |
匹配1s后的递归调用是
(即右侧不是 []:[],它与 [[]] 相同,一个元素列表,其唯一元素是空列表)并且您没有匹配的模式第一个参数为非空,第二个为空。
- 谢谢。所以每次我只剩下一个元素时,即 [a] ,当我进入递归并得到他的"xs" 时,我总是会得到 []?例如:(x:xs) 而我只有 x 即 1,所以它是 (1:[]) 而"xs"是 []?