在 Haskell 中配对相邻列表项
我有一个像这样的链表
["root", "foo", "bar", "blah"]
,我想使用相邻对将其转换为元组列表。像这样
[("root", "foo"), ("foo", "bar"), ("bar", "blah")]
目前,我正在使用这个来做到这一点:
zipAdj x = tail (zip ("":x) (x++[""]))
但是,我不太喜欢这种方法。有人能想出更好的办法吗?如果这是显而易见的,我道歉,我对 Haskell 相当陌生。
I have a chained list like
["root", "foo", "bar", "blah"]
And I'd like to convert it to a list of tuples, using adjacent pairs. Like so
[("root", "foo"), ("foo", "bar"), ("bar", "blah")]
At the moment, I'm using this to do it:
zipAdj x = tail (zip ("":x) (x++[""]))
However, I don't really like this method. Can anyone think of a better way? If it's glaringly obvious I apologise, I'm fairly new to Haskell.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好的,这是作为答案的评论:
只需
zipAdj x = zip x $ tail x
就足够了。zip
在到达两个列表中较短的一个的末尾时停止,因此这只是将列表中的每个项目与其后继项目配对,这似乎就是您想要的。为了解释毫无意义的版本:
zip <*>; tail
使用 Applicative 实例来表示“某种类型的函数”,这基本上相当于一个轻量级内联 Reader monad——在这种情况下,列表是 Reader 的“环境”。通常这只会混淆问题,但在这种情况下,它几乎使它变得更清晰,假设您知道在这里阅读(<*>)
为“将这两个应用于单个参数,然后应用第一个到第二个”。Okay, here's the comment as an answer:
Just
zipAdj x = zip x $ tail x
will suffice.zip
stops upon reaching the end of the shorter of the two lists, so this simply pairs each item in the list with its successor, which seems to be all you want.And for the sake of explaining the pointless version:
zip <*> tail
uses theApplicative
instance for "functions from some type", which basically amounts to a lightweight inline Reader monad--in this case the list is the "environment" for the Reader. Usually this just obfuscates matters but in this case it almost makes it clearer, assuming you know to read(<*>)
here as "apply both of these to a single argument, then apply the first to the second".一种可能的解决方案:
绝对不像你的那么小,并且可能可以优化很多。
One possible solution:
Definitely not as small as yours, and can probably be optimized quite a bit.
可以将问题中的
zipAdj
推广到任意Traversable
容器。如果我们想要在前端添加额外的元素,我们会这样做:要将额外的元素粘贴在末尾,我们可以使用
mapAccumR
:这可以有效地向后遍历容器嗯>。
以这种方式概括显然所需的函数是不可能的,但可以以不同的方式概括它:
这给出
It's possible to generalize the
zipAdj
in the question to work with arbitraryTraversable
containers. Here's how we'd do it if we wanted the extra element on the front end:To stick the extra element on the end, we can use
mapAccumR
:This effectively traverses the container backwards.
It's impossible to generalize the apparently-desired function in quite this fashion, but it's possible to generalize it a bit differently:
This gives