可以使用模式匹配来绑定列表的最后一个元素吗?
由于有一种方法可以通过模式匹配来绑定列表的头和尾,我想知道是否可以使用模式匹配来绑定列表的最后一个元素?
Since there is a way to bind the head and tail of a list via pattern matching, I'm wondering if you can use pattern matching to bind the last element of a list?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
是的,您可以使用
ViewPatterns
扩展。请注意,此模式总是会成功,因此您可能需要为列表为空的情况添加一个模式,否则
last
将引发异常。另请注意,这只是语法糖。与普通模式匹配不同,这是 O(n),因为您仍在访问单链表的最后一个元素。如果您需要更有效的访问,请考虑使用不同的数据结构,例如 < code>Data.Sequence,它提供对两端的 O(1) 访问权限。
Yes, you can, using the
ViewPatterns
extension.Note that this pattern will always succeed, though, so you'll probably want to add a pattern for the case where the list is empty, else
last
will throw an exception.Also note that this is just syntactic sugar. Unlike normal pattern matching, this is O(n), since you're still accessing the last element of a singly-linked list. If you need more efficient access, consider using a different data structure such as
Data.Sequence
, which offers O(1) access to both ends.您可以使用
ViewPatterns
在列表末尾进行模式匹配,所以让我们使用
reverse
作为 viewFunction,因为它总是成功,所以例如这是安全的从某种意义上说,只要您涵盖了所有可能性,它就不会抛出任何异常。
(例如,您可以重写它以返回
Maybe
。)语法
mainFunction (viewFunction ->pattern) = resultExpression
的语法糖
是
mainFunction x = 。 case viewFunction x 的模式 -> resultExpression
所以你可以看到它实际上只是反转列表然后模式匹配它,但感觉更好。
viewFunction
是您喜欢的任何函数。(扩展的目的之一是让人们能够干净、轻松地使用访问器函数
用于模式匹配,因此他们不必在以下情况下使用其数据类型的底层结构:
在其上定义函数。)
You can use
ViewPatterns
to do pattern matching at the end of a list, so let's doand use
reverse
as the viewFunction, because it always succeeds, so for exampleThis is safe in the sense that it doesn't throw any exceptions as long as you covered all the possibilities.
(You could rewrite it to return a
Maybe
, for example.)The syntax
mainFunction (viewFunction -> pattern) = resultExpression
is syntactic sugar for
mainFunction x = case viewFunction x of pattern -> resultExpression
so you can see it actually just reverses the list then pattern matches that, but it feels nicer.
viewFunction
is just any function you like.(One of the aims of the extension was to allow people to cleanly and easily use accessor functions
for pattern matching so they didn't have to use the underlying structure of their data type when
defining functions on it.)
其他答案解释了基于 ViewPatterns 的解决方案。如果你想让它更像模式匹配,你可以将其打包到
PatternSynonym
中:然后将你的函数编写为例如
The other answers explain the
ViewPatterns
-based solutions. If you want to make it more pattern matching-like, you can package that into aPatternSynonym
:and then write your function as e.g.
这是我学习 Haskell 编程的第一天,我也遇到了同样的问题,但我无法按照之前的解决方案中的建议使用某种外部工件。
我对 Haskell 的感觉是,如果核心语言无法解决你的问题,那么解决方案就是改变你的问题,直到它适用于该语言。
在这种情况下,转换问题意味着将尾部问题转换为头部问题,这似乎是模式匹配中唯一支持的操作。事实证明,您可以使用列表反转轻松地做到这一点,然后使用头元素处理反转列表,就像在原始列表中使用尾元素一样,最后,如果需要,将结果恢复到初始顺序(例如,如果这是一个列表)。
例如,给定一个整数列表(例如[1,2,3,4,5,6]),假设我们要构建这个列表,其中原始列表中从末尾开始的每个第二个元素都被替换为它的双(练习取自家庭作业1 href="http://www.cis.upenn.edu/~cis194/spring13/lectures.html" rel="nofollow noreferrer">这篇关于 Haskell 的精彩介绍) : [2,2,6,4 ,10,6]。
然后我们可以使用以下内容:
它显然比以前的解决方案长得多,但对我来说感觉更像 Haskell 风格。
This is my first day of Haskell programming and I also encountered the same issue, but I could not resolve to use some kind of external artifact as suggested in previous solutions.
My feeling about Haskell is that if the core language has no solution for your problem, then the solution is to transform your problem until it works for the language.
In this case transforming the problem means transforming a tail problem into a head problem, which seems the only supported operation in pattern matching. It turns that you can easily do that using a list inversion, then work on the reversed list using head elements as you would use tail elements in the original list, and finally, if necessary, revert the result back to initial order (eg. if it was a list).
For example, given a list of integers (eg. [1,2,3,4,5,6]), assume we want to build this list in which every second element of the original list starting from the end is replaced by its double (exercise taken from Homework1 of this excellent introduction to Haskell) : [2,2,6,4,10,6].
Then we can use the following:
It's obviously much longer than previous solutions, but it feels more Haskell-ish to me.