haskell - 请帮助我理解 haskell 中的模式匹配。我有点困惑

标签 haskell list design-patterns match

如果我有这样的东西:

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` [] 

我会得到:False(它应该是 True)。
是不是因为第一个模式在他的右边有元素:(x:xs),正因为如此,x 必须有一个值,所以我通过了第一个模式,然后进入第二个模式:

list   `myIsPrefixOf`  []      = False

哪个匹配,返回False。
我说得对吗?

如果我是对的,那么区别在于如果我写(x:xs)x 必须是一个值而不是[].
另一方面,如果我写 list,它可以匹配 [][a][a,a ,a] (etc'),因此,第二个模式的 list 将匹配我输入中的第一个 [],并且所以我会得到 False ?
(和以前一样,在 [a] 中,我的意思是它是一个包含一个数字的列表,而 [a,a,a] 是包含三个数字的列表)。

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

[]     <code>myIsPrefixOf</code>  (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)

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

最佳答案

你对第一个问题的理解是正确的,但是你对第二个问题的理解是错误的。

要了解原因,请从实际功能退一步并查看列表。列表有两个构造函数,[]:。因此,完整的模式匹配需要涵盖这两种情况。

您的函数有两个列表参数,因此您需要涵盖 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]

the function pass through the first pattern and get to the second one:

(l:ls) `myIsPrefixOf` (x:xs) = if l == x then ls `myIsPrefixOf` xs
                               else False

so:

[1,2] `myIsPrefixOf` [1]

and:

l == x.

到目前为止还不错。

they both 1, so i match again the second pattern:

等等,稍等片刻,找出这里的所有值。我们已经知道 l==x==1。还有 ls==[2]xs==[]

现在当我们重复出现时,ls 不会匹配第一个模式(它不是空的),但是 xs 不会匹配第二个模式(它是空的,并且(x:xs) 需要一个 : 对象,而不是 [])。因此该函数因“非详尽模式”而崩溃。

关于haskell - 请帮助我理解 haskell 中的模式匹配。我有点困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2101740/

相关文章:

design-patterns - 在通知系统中每个通知插入多少行?

haskell - VSCode 在附加模块的 Haskell 扩展中没有智能感知

haskell - 反射是否有不连贯的风险?

haskell - 如何在 Scotty Action 中使用 System.command

javascript - 嵌套列表的树形导航

java - 如何使用接口(interface)或抽象类隐藏实现类

haskell - 重叠实例可以,但仍然失败

php - 如何从 Stacey App 中的逗号分隔列表值创建链接标签?

python - 我可以使用 %f 和 %d 将 float 和整数格式化为列表中的字符串吗?

java - 多重继承之类的?