【问题标题】:What is the practical use for laziness as a built-in language feature?惰性作为内置语言功能的实际用途是什么?
【发布时间】:2011-11-26 16:21:19
【问题描述】:

很明显,为什么想要懒惰的函数式编程语言需要是纯的。我在看相反的问题:如果一种语言想要纯粹,那么懒惰有很大的优势吗? Haskell 的一位设计师提出的一个论点是,它消除了诱惑。也许吧,但我正在尝试权衡更具体的优势。

鉴于你想做函数式编程,有哪些用例可以让内置的惰性让你更清晰、更简单或更简洁地表达事物?

简单地说:为什么懒惰如此重要,以至于您想将其构建到语言中?

(我正在寻找更面向应用程序而不是演示的用例 - 我知道您可以通过过滤无限的自然数列表来生成无限的素数列表,但是谁在午餐前写了十次那个...)

【问题讨论】:

  • 这是一个有趣的话题,但是您以一种相当不幸的方式提出这个问题,本质上是在请求人们可以想象惰性评估有用的任何场景。如果您正在设计一种语言,您最好专注于您正在尝试做出的具体决定,并在权衡选项时请求帮助,以便您做出明智的选择。
  • 我不知道你是否会在这里得到好的答案,这个问题更多是针对编程语言设计人员而不是程序员。这是site about computer science 会更好地解决的问题。我推荐文章cited on Wikipedia(不是 WP 文章本身),尤其是“为什么 FP 很重要”。
  • rwallace:基于@Gilles 的编辑,我进一步修改以强调问题懒惰是一个内置功能(使用示例来说明而不是示例作为最终目标),并且在假设这是可以接受的情况下重新打开。如果您不同意,请讨论。
  • 很好,谢谢,我同意编辑,他们澄清了问题。至于维基百科上引用的文章,它们当然包含很多有用的信息,但如果它们包含很多关于懒惰作为一种语言特性的实际用例的讨论,我就错过了。

标签: programming-languages functional-programming language-design lazy-evaluation


【解决方案1】:

“在另一个地方需要它之前,什么都不会被评估”是一个简化的比喻,它没有涵盖惰性评估的所有方面(例如,它没有提到严格现象)。

从理论上讲,在设计纯语言时有 3 种方法可供选择(当然,如果它基于某种 lambda 演算,而不是更奇特的评估模型):严格、非严格和全面。

各有优缺点,需要阅读相应的研究论文。

总的语言是这三种语言中最纯粹的。在另外两个中,非终止可以被视为副作用,因此必须构建严格性和整体性分析器以保持实现高效。两种分析都无法确定,因此分析器永远不会完整。

但是,所有语言的表达能力都最低:所有语言不可能是图灵完备的。获得足够好的表达能力的一种常见方法是为有根据的递归提供内置证明系统,这并不比非全部语言的分析器更容易构建。

从实际的角度来看,非严格语义可以让您更轻松地定义控制抽象,因为控制结构本质上是非严格的。在严格的语言中,您仍然需要一些具有非严格语义的地方。例如。 if 结构即使在严格的语言中也具有非严格语义。

因此,如果您的语言是严格的,控制结构是一种特殊情况。相比之下,非严格语言可以一律是非严格的——它在严格结构中没有内在的需求。

至于“谁在午餐前写了十次”——任何使用 Haskell 进行项目的人都会这样做。我认为使用一种语言(在您的情况下是一种非严格语言)开发一个非玩具项目是掌握其优缺点的最佳方式。

以下是一些非玩具示例说明的懒惰的通用用例:

  1. 控制流难以预测的情况。当没有惰性时,请考虑属性语法,您必须对属性执行拓扑排序以解决依赖关系。每次更改依赖关系图时重新排序代码是不切实际的。在 Haskell 中,您可以在没有显式排序的情况下实现属性语法形式,并且在 Hackage 上至少有两个实际实现。属性文法在编译器构造中有着广泛的应用。

  2. 解决许多优化问题的“生成和搜索”方法。在严格的语言中,您必须交错生成和搜索,在 Haskell 中,您只需编写单独的生成和搜索函数,并且您的代码在语法上保持模块化,但在运行时交错。想想旅行商问题 (TSP),当您生成所有可能的旅行,然后使用分支定界算法搜索它们时。请注意,分支边界算法仅检查游览的某些第一个城市,仅生成路线的必要部分。即使在最纯粹的配方中,TSP 也有多种应用,例如规划、物流和微芯片的制造。稍作修改后,它在许多领域(例如 DNA 测序)中似乎是一个子问题。

  3. 惰性代码具有非模块化控制流,因此单个函数可以有许多可能的控制流,具体取决于它执行的环境。这种现象可以看作是某种“控制流多态性”,因此很惰性控制流抽象比严格的抽象更通用,高阶函数的标准库在惰性语言中更有用。想想 Python 生成器、循环和列表迭代器:在 Haskell 中,列表函数涵盖了所有三个用例,由于惰性,控制流适应不同的使用场景。它不仅限于列表 - 想想 Data.Arrow 和 iteratees,State monad 的惰性和严格版本等。还要注意,非模块化控制流既是优点也是缺点,因为它使性能推理变得更加困难。

  4. 惰性可能无限的数据结构在玩具示例之外很有用。参见 Conal Elliott 关于使用尝试记忆高阶函数的作品。无限数据结构表现为无限搜索空间(参见 2)、无限循环和 Python 意义上的永不耗尽的生成器(参见 3)。

【讨论】:

  • 上述比喻的来源似乎是 Henderson 和 Morris,POPL'76 的“一个懒惰的评估者”
【解决方案2】:

Mac OS X 的 Core Image 是惰性求值的一个很好的实用示例。

基本上,Core Image 可让您创建图像生成器和过滤器的有向无环图。直到过程的最后一步:实现才真正进行评估。当您请求物化 Core Image 图时,最终的图像帧会通过图的变换向后传播,从而最大限度地减少需要评估的实际像素值的数量。

【讨论】:

    【解决方案3】:

    Hughes 的经典著作Why Functional Programming Matters 对这一点进行了广泛的讨论。其中,Hughes 使用许多可访问的示例认为,惰性允许改进模块化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-02
      • 2019-05-17
      • 2015-04-22
      • 2021-07-22
      • 1970-01-01
      • 2010-10-17
      • 2011-09-20
      • 2015-06-07
      相关资源
      最近更新 更多