无限数据结构有哪些引人注目的用例?
某些语言(Haskell、Clojure、Scheme 等)具有惰性求值。惰性求值的“卖点”之一是无限的数据结构。这有什么了不起的?能够处理无限数据结构明显具有优势的例子有哪些?
Some languages (Haskell, Clojure, Scheme, etc.) have lazy evaluation. One of the "selling points" of lazy evaluation is infinite data structures. What is so great about that? What are some examples of cases where being able to deal with infinite data structures is clearly advantageous?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这里有两个例子,一大一小:
为什么功能性John Hughes 的《Programming Matters》有一个很好的例子,即国际象棋游戏。国际象棋游戏的走棋树实际上并不是无限的,但它足够大,以至于它也可能是无限的(称之为“接近无限”)。用严格的语言来说,你实际上不能将其视为一棵树,因为没有足够的空间来存储整棵树。但在惰性语言中,您只需定义树,然后定义一个“nextMove”函数来根据需要遍历它。惰性求值机制负责处理细节。
这个小例子只是将索引号与列表中的每个项目相关联,以便 ["foo", "bar", "baz"] 变为 [(1,"foo"), (2,"bar"), ( 3、“巴兹”)]。在严格的语言中,您需要一个循环来跟踪最后一个索引并检查是否位于末尾。在 Haskell 中你只需说:
zip 的第一个参数是一个无限列表。您无需计算需要提前多长时间。
Here are two examples, one big and one small:
Why Functional Programming Matters by John Hughes has a good example, of a chess game. The move tree for a chess game is not actually infinite, but its big enough that it might as well be infinite (call it "near-infinite"). In a strict language you can't actually treat it as a tree, because there isn't enough room to store the whole tree. But in a lazy language you just define the tree and then define a "nextMove" function to traverse it as far as necessary. The lazy evaluation mechanism takes care of the details.
The small example is simply associating an index number with every item in a list, so that ["foo", "bar", "baz"] becomes [(1,"foo"), (2,"bar"), (3,"baz")]. In a strict language you need a loop that keeps track of the last index and checks to see if you are at the end. In Haskell you just say:
The first argument to zip is an infinite list. You don't need to work out how long it needs to be ahead of time.
我能想到的一些优点:
O(n^2)
到O(n log n)
),那么这可以是一个巨大的胜利。A few advantages I can think of:
O(n^2)
toO(n log n)
) then this can be a big win.有一个规范的纯记忆策略:
我们将 fib' 函数映射到一个无限列表上,以构建一个包含
fib
的所有值的表。瞧!便宜,容易记忆。当然,这在参数中具有线性的查找时间。您可以将其替换为无限特里树以获得对数查找时间。参见data-inttrie。
There is the canonical pure memoization strategy:
We map the
fib'
function over an infinite list to construct a table of all the values offib
. Voila! Cheap, easy memoization.Of course, this has lookup time linear in the argument. You can replace it with an infinite trie to get logarithmic lookup time. cf. data-inttrie.
我要评论@knivil 的计划。相反,我将把这个作为另一个答案。
惰性数据结构并不是完成大多数任务的唯一方法。这可能会激怒 Python 爱好者。但我相信程序员最好能够选择他们使用的技术。懒惰的技术是强大而优雅的。
Knivil 提到使用Scheme 的iota。看看依靠惰性编写完整的方法(包含所有 3 个参数)是多么容易:
我还可以通过滥用惰性为非空列表编写
length
:考虑强大而优雅的
Prelude 中定义的 iterate
函数。它创建无限列表
[x, fx, f (fx), f (f (fx)), ...]
。我本可以用迭代的方式来编写 iota:惰性方法是一种优雅的编程方式。这不是唯一的方法,习惯了 C 或 Java 的人肯定会大喊“但我不需要懒惰,我可以_”,他们是对的。如果你的语言是图灵完备的,那就可以做到。但懒惰也可以如此优雅。
I was going to comment regarding @knivil's Scheme. Instead I'll just throw this up as another answer.
Lazy data structures aren't the only way to accomplish most tasks. This might irritate Pythonistas. But I believe it's best when programmers get to choose which techniques they use. Lazy techinques are powerful and elegant.
Knivil mentioned using Scheme's
iota
. Look how easy it is to write the full method (with all 3 args), relying on laziness:I could also write
length
for non-empty lists by abusing laziness:Consider the powerful and elegant
iterate
function defined in Prelude.It creates the infinite list
[x, f x, f (f x), f (f (f x)), ...]
. I could have writteniota
in terms ofiterate
:The lazy approach is an elegant way to program. It's not the only way, and people used to C or Java will certainly cry out "but I don't need laziness, I can just _", and they are correct. If your language is Turing-complete, it can be done. But laziness can be oh so elegant.
嗯,上个月我有一个很好的用例。我需要一个在复制对象时生成唯一名称的生成器。这意味着,生成器采用原始名称
X
,并为副本生成一个新名称。它通过附加文本来实现这一点,只要该名称未在同一组内的对象集中使用即可。使用“无限数据结构”(无限的字符串数组)而不是简单的循环有一个优点:如果名称已在使用中,您可以将名称生成部分与测试完全分开。因此,我可以为不同类型的对象重用生成器函数,其中每种对象类型的使用中测试略有不同。
Well, I had a nice use case for that last month. I needed a generator for unique names when copying objects. That means, the generator takes the original name
X
, and generates a new name for the copy. It does that by appending a text likeas long as the name is not used within the set of objects within the same group. Using an "infinite data structure" (an infinite array of strings) for that instead of a simple loop has one advantage: you can separate the name generating part completely from the test if the name is already in use. So I could reuse the generator function for different types of objects where the in-use test is slightly different for each object type.
无限数据结构提供了(可计算)实数的优雅表示。例如,像这样的无限列表
可以表示
pi
。由于内置了惰性,对此表示的操作变得很容易。Infinite data structures provide elegant representations of (computable) real numbers. For example, an infinite list like
can represent
pi
. WIth built in laziness, operating on this representation becomes easy.