我正在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,_,_]
,依此类推。我该如何阻止它?
答案 0 :(得分:4)
当您使用列入列表的函数时,通常需要使用递归和列表元素函数。
让我们来看看你到目前为止所做的事情。
在第四行,当您收到包含三个元素的列表时,您将构建评估结果:
this
在第三行,当您收到两个元素的列表时,您的构建评估如下:
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
,{{1 }和tail
。
在函数的每个模式中,我们只分别处理列表的最后一个元素。然后将非最后一个元素传递回last
。因此,我们可以通过使用init
来访问列表的最后一个元素来消除一些模式匹配,并使用build
来获取除最后一个元素之外的所有元素。
last
通过使用init
和build :: [LogMessage] -> MessageTree
build [x] = Node Leaf x Leaf
build l = Node (build (init l)) (last l) Leaf
处理常规列表元素,而不是使用列表中明确指定的元素,我们可以消除对无限模式匹配的需要。
答案 1 :(得分:2)
以正向计算,累积式重写代码:
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)
模式?
答案 2 :(得分:1)
您可能喜欢模式x:xs
,它匹配任何(非空)列表,将x
绑定到第一个元素,将xs
绑定到其余元素。它通常与递归定义结合使用,无论列表有多长,依次检查列表的每个元素。
如果您希望匹配比三个元素更长的列表,则该模式可以扩展为x:y:z:rest
;在这种情况下,x
,y
和z
将绑定到列表的前三个元素,rest
将绑定到其余元素。
答案 3 :(得分:1)
你需要递归地编写这个函数,通过找到一种方法来根据一个更简单的情况解决一个复杂的案例。因为模式匹配是一个列表,所以您将使用(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