Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Data structures 无限数据结构的一些引人注目的用例是什么?_Data Structures_Haskell_Clojure_Scheme_Lazy Sequences - Fatal编程技术网

Data structures 无限数据结构的一些引人注目的用例是什么?

Data structures 无限数据结构的一些引人注目的用例是什么?,data-structures,haskell,clojure,scheme,lazy-sequences,Data Structures,Haskell,Clojure,Scheme,Lazy Sequences,有些语言(Haskell、Clojure、Scheme等)具有惰性求值。惰性评估的“卖点”之一是无限的数据结构。这有什么了不起的?能够处理无限数据结构显然有利的情况有哪些?有一种规范的纯记忆策略: fib = (map fib' [0..] !!) where fib' 0 = 0 fib' 1 = 1 fib' n = fib (n-1) + fib (n-2) 我们将fib'函数映射到一个无限列表上,以构建一个包含fib所有值的表。瞧!便宜,容易记忆 当然,

有些语言(Haskell、Clojure、Scheme等)具有惰性求值。惰性评估的“卖点”之一是无限的数据结构。这有什么了不起的?能够处理无限数据结构显然有利的情况有哪些?

有一种规范的纯记忆策略:

fib = (map fib' [0..] !!)
    where
    fib' 0 = 0
    fib' 1 = 1
    fib' n = fib (n-1) + fib (n-2)
我们将
fib'
函数映射到一个无限列表上,以构建一个包含
fib
所有值的表。瞧!便宜,容易记忆


当然,这在参数中具有线性查找时间。您可以用一个无限的trie替换它,以获得对数查找时间。cf..

上个月我有一个很好的用例。复制对象时,我需要一个唯一名称生成器。这意味着,生成器采用原始名称
X
,并为副本生成新名称。它通过添加一个文本来实现这一点,如

X - copy
X - copy (2)
X - copy (3)
...

只要名称未在同一组中的对象集中使用。使用“无限数据结构”(字符串的无限数组)代替简单循环有一个优点:如果名称已经在使用中,您可以将名称生成部分与测试完全分离。因此,我可以为不同类型的对象重用生成器函数,其中每个对象类型的在用测试略有不同

这里有两个例子,一个大一个小:

约翰·休斯有一个很好的国际象棋例子。国际象棋游戏的移动树实际上并不是无限的,但它足够大,以至于它也可以是无限的(称之为“接近无限”)。严格来说,你不能把它当作一棵树,因为没有足够的空间来存放整棵树。但是在惰性语言中,您只需定义树,然后定义一个“nextMove”函数来尽可能地遍历它。惰性评估机制负责处理细节

一个小例子是简单地将索引号与列表中的每个项目关联,这样[“foo”,“bar”,“baz”]就变成[(1,“foo”),(2,“bar”),(3,“baz”)]。在严格的语言中,您需要一个循环来跟踪最后一个索引,并检查是否在末尾。在哈斯克尔,你只是说:

zip [1..] items

zip的第一个参数是一个无限列表。你不需要计算它需要提前多长时间。

我能想到的几个优点:

  • 更干净的代码-有趣的是,如果生成无限序列的代码通常比在有界数据上操作的代码更简单、更干净,那么它就可以生成无限序列。这是因为这样的代码通常更接近底层的数学定义
  • 灵活性-如果使用惰性无限结构编写数据,则无需担心,而无需提前决定数据需要多大。它将“起作用”
  • 性能-如果您正确使用惰性,您可以使用它来提高性能,只需在需要时计算数据值,而且可能根本不需要。因此,您可以潜在地避免大量不必要的计算
  • 无限进程的抽象-无限延迟序列作为事件流的抽象有一个有趣的用途,例如,随着时间的推移从网络连接读取输入。这可以创建一些非常优雅和有趣的方法来创建代码来处理事件流。e、 g.见Clojure的图书馆
  • 更好的算法-有一些算法更容易用无限的数据结构表达-想法是你懒散地“拉入”您需要的解决方案部分,同时不计算无限算法的其余部分。如果使用此方法可以降低算法的时间复杂度(例如从
    O(n^2)
    O(n log n)
    ),那么这将是一个巨大的胜利

我打算对@knivil的计划发表评论。相反,我会把这个作为另一个答案

惰性数据结构不是完成大多数任务的唯一方法。这可能会激怒蟒蛇。但我相信最好是程序员选择他们使用的技术。懒惰的技术是强大而优雅的

Knivil提到使用方案的
物联网
。看一看,依赖惰性编写完整方法(包含所有3个参数)有多么容易:

iota count begin step = let xs = begin:map (+step) xs
                        in take count xs

-- or, alternately
iota count begin step = take count $ map ((+begin).(*step)) [0..]
len = fst . last . zip [1..]

-- or even handling empty lists
len = fst . last . zip [0..] . (undefined:)
我还可以通过滥用惰性为非空列表编写
length

iota count begin step = let xs = begin:map (+step) xs
                        in take count xs

-- or, alternately
iota count begin step = take count $ map ((+begin).(*step)) [0..]
len = fst . last . zip [1..]

-- or even handling empty lists
len = fst . last . zip [0..] . (undefined:)
请考虑Prelude中定义的强大而优雅的
iterate
函数

iterate f x = x : iterate f (f x)
它创建无限列表
[x,fx,f(fx),f(f(fx)),…]
。我本可以用迭代的方式编写物联网:

iota count begin step = take count $ iterate (+step) begin

惰性方法是一种优雅的编程方式。这不是唯一的方法,习惯C或Java的人肯定会喊出“但我不需要懒惰,我可以u”,他们是正确的。如果您的语言是图灵完备的,则可以完成。但是懒惰是如此优雅。

无限数据结构提供了(可计算)实数的优雅表示。例如,一个无限列表,如

[(0, 4), (1, 3.5), (3.1, 3.2), ...]

可以表示
pi
。有了内置的惰性,对这种表示进行操作变得很容易。

这是一段优雅的代码。但是(也许我不完全理解引擎盖下到底发生了什么)这种方式比在表中缓存结果的动态编程方式更好吗?@Anas这是在表中缓存结果的动态编程方式。本例中的表是一个无限列表。虽然DP通常涉及对表进行显式迭代。使用惰性备忘表可以让您像DP一样编写,但只评估实际用于所需结果的子问题。您的小示例很糟糕。在方案中,您使用
(地图cons(物联网(长度项目))项目)
,其中
物联网
来自srfi-1。你不需要一个循环。@knivil:你需要