如何停止 Haskell 中的无限模式匹配?
How to stop infinite pattern-matching in Haskell?
我正在做 http://www.cis.upenn.edu/~cis194/spring13/lectures.html
作业 2 中的练习 3
build :: [LogMessage] -> MessageTree
build [x] = Node Leaf x Leaf
build [x,y] = Node (build [x]) y Leaf
build [x,y,z] = Node (Node (build [x]) y Leaf) z Leaf
我有一个问题,我不知道如何结束模式匹配。它只会继续扩展到 [x,y,z,_]
然后 [x,y,z,_,_]
等等。我该如何阻止它?
您可能喜欢 x:xs
模式,它匹配任何(非空)列表,将 x
绑定到第一个元素,将 xs
绑定到其余元素。它通常与递归定义结合使用,以依次检查列表的每个元素,无论列表有多长。
如果你想匹配比三个元素更长的列表,模式可以扩展到x:y:z:rest
;在这种情况下,x
、y
和 z
将绑定到列表的前三个元素,而 rest
将绑定到其余元素。
你需要递归地编写这个函数,方法是找到一种方法,使一个复杂的案例可以用一个更简单的案例来解决。因为您要进行模式匹配的是列表,所以您将使用 (x:xs)
模式将列表分解为头部和尾部。像这样:
build :: [LogMessage] -> MessageTree
build [] = ... -- remember lists can be empty!
build [x] = Node Leaf x Leaf
build (x:xs) = -- something to do with build [x] and xs
以前向计算、累积的方式重写您的代码:
build [x] = go Leaf [x]
where
go tree (x:xs) = go (Node tree x Leaf) xs -- build up ("accumulate") the tree
go tree [] = tree -- and reduce the list until empty
build [x,y] = go (Node Leaf x Leaf) [y] -- can we use another, simpler
where -- initial accumulator value?
go tree (x:xs) = go (Node tree x Leaf) xs
go tree [] = tree
....
你现在能简化一下吗?你注意到这里的相似之处了吗?可以使用任意长度的列表调用 build
,即匹配 (x:xs)
模式吗?
当您使用接受列表的函数时,您通常会希望使用递归和列表元素函数。
让我们看看你目前有什么。
在第四行,当它接收到一个包含三个元素的列表时,您已构建了以下评估:
build [x,y,z] = Node (Node (build [x]) y Leaf) z Leaf
在第三行,当它收到一个包含两个元素的列表时,您的构建评估如下:
build [x,y] = Node (build [x]) y Leaf
如果您查看这两行,您会注意到其中有一些重复。具体来说,两者都包含 Node (build [x]) y Leaf
。当出现这样的重复时,递归可以提供帮助。
使用递归,您可以用包含两个元素的列表递归调用构建函数来替换重复。例如,您可以将第四行替换为:
build [x,y,z] = Node (build [x,y]) z Leaf
这样简单了一些,但还没有解决问题。
build :: [LogMessage] -> MessageTree
build [x] = Node Leaf x Leaf
build [x,y] = Node (build [x]) y Leaf
build [x,y,z] = Node (build [x,y]) z Leaf
如果您看一下新函数,您会发现我们正在使用的一些常量可以使用列表元素函数替换,例如 head
、tail
、last
, 和 init
.
在函数的每个模式中,我们只单独处理列表的最后一个元素。然后将非最后一个元素传递回 build
。因此,我们可以通过使用 last
来访问列表的最后一个元素,并使用 init
来获取除最后一个元素之外的所有元素,从而摆脱一些模式匹配。
build :: [LogMessage] -> MessageTree
build [x] = Node Leaf x Leaf
build l = Node (build (init l)) (last l) Leaf
通过使用 init
和 last
处理一般列表元素,而不是处理明确指定的列表元素,我们可以消除无限模式匹配的需要。
我正在做 http://www.cis.upenn.edu/~cis194/spring13/lectures.html
作业 2 中的练习 3build :: [LogMessage] -> MessageTree
build [x] = Node Leaf x Leaf
build [x,y] = Node (build [x]) y Leaf
build [x,y,z] = Node (Node (build [x]) y Leaf) z Leaf
我有一个问题,我不知道如何结束模式匹配。它只会继续扩展到 [x,y,z,_]
然后 [x,y,z,_,_]
等等。我该如何阻止它?
您可能喜欢 x:xs
模式,它匹配任何(非空)列表,将 x
绑定到第一个元素,将 xs
绑定到其余元素。它通常与递归定义结合使用,以依次检查列表的每个元素,无论列表有多长。
如果你想匹配比三个元素更长的列表,模式可以扩展到x:y:z:rest
;在这种情况下,x
、y
和 z
将绑定到列表的前三个元素,而 rest
将绑定到其余元素。
你需要递归地编写这个函数,方法是找到一种方法,使一个复杂的案例可以用一个更简单的案例来解决。因为您要进行模式匹配的是列表,所以您将使用 (x:xs)
模式将列表分解为头部和尾部。像这样:
build :: [LogMessage] -> MessageTree
build [] = ... -- remember lists can be empty!
build [x] = Node Leaf x Leaf
build (x:xs) = -- something to do with build [x] and xs
以前向计算、累积的方式重写您的代码:
build [x] = go Leaf [x]
where
go tree (x:xs) = go (Node tree x Leaf) xs -- build up ("accumulate") the tree
go tree [] = tree -- and reduce the list until empty
build [x,y] = go (Node Leaf x Leaf) [y] -- can we use another, simpler
where -- initial accumulator value?
go tree (x:xs) = go (Node tree x Leaf) xs
go tree [] = tree
....
你现在能简化一下吗?你注意到这里的相似之处了吗?可以使用任意长度的列表调用 build
,即匹配 (x:xs)
模式吗?
当您使用接受列表的函数时,您通常会希望使用递归和列表元素函数。
让我们看看你目前有什么。
在第四行,当它接收到一个包含三个元素的列表时,您已构建了以下评估:
build [x,y,z] = Node (Node (build [x]) y Leaf) z Leaf
在第三行,当它收到一个包含两个元素的列表时,您的构建评估如下:
build [x,y] = Node (build [x]) y Leaf
如果您查看这两行,您会注意到其中有一些重复。具体来说,两者都包含 Node (build [x]) y Leaf
。当出现这样的重复时,递归可以提供帮助。
使用递归,您可以用包含两个元素的列表递归调用构建函数来替换重复。例如,您可以将第四行替换为:
build [x,y,z] = Node (build [x,y]) z Leaf
这样简单了一些,但还没有解决问题。
build :: [LogMessage] -> MessageTree
build [x] = Node Leaf x Leaf
build [x,y] = Node (build [x]) y Leaf
build [x,y,z] = Node (build [x,y]) z Leaf
如果您看一下新函数,您会发现我们正在使用的一些常量可以使用列表元素函数替换,例如 head
、tail
、last
, 和 init
.
在函数的每个模式中,我们只单独处理列表的最后一个元素。然后将非最后一个元素传递回 build
。因此,我们可以通过使用 last
来访问列表的最后一个元素,并使用 init
来获取除最后一个元素之外的所有元素,从而摆脱一些模式匹配。
build :: [LogMessage] -> MessageTree
build [x] = Node Leaf x Leaf
build l = Node (build (init l)) (last l) Leaf
通过使用 init
和 last
处理一般列表元素,而不是处理明确指定的列表元素,我们可以消除无限模式匹配的需要。