haskell - 这是我懒惰的分区吗?

时间:2016-03-09 17:28:15

标签: haskell lazy-evaluation

例如

partitions [1,2,3] =
  [([],[1,2,3])
  ,([1],[2,3])
  ,([1,2],[3])
  ,([1,2,3],[])]
partitions :: [a] -> [([a], [a])]
partitions (x:xs) = ([], x:xs):[(x:ys, rs) | (ys, rs) <- partitions xs]

我想知道它是否是懒惰的解决方案。例如partitions [1..]是无限的。此外,take 5 $ partitions [1..]也是无限的。鉴于此函数的结果是无限的,我认为这很明显。但是,如果我正确地理解懒惰,我不确定它是否是懒惰的。

1 个答案:

答案 0 :(得分:6)

有不同程度的懒惰。

有人可能会说你的函数是严格的,因为partitions undefined会触发一个异常,但那太迂腐了。

可能是&#34;懒惰&#34;你实际上是指&#34;它只会在访问输入的一部分后产生输出的一部分&#34;。然后出现几度懒惰,这取决于输出的每个部分需要多少输入。

在您的情况下,函数的形状如下:

foo [] = (some constant value)
foo (x:xs) = C expression1 ... expressionN

其中C是值构造函数。更确切地说,C = (:)N=2。由于Haskell构造函数是惰性的(除非涉及bang注释),foo (x:xs)的结果将始终为非底部:在输入列表中使用元素足以生成输出列表的元素。

您可能会对partitions [1..]的输出感到困惑,(xs, ys)是一对无限的ys列表,其中每个partitions (x:xs) = case partitions xs of [] -> expression0 (y:ys) -> expression1 : expression2 都是无限列表。这使得懒惰的概念变得更加复杂,因为您现在可能想知道,例如,&#34;我获取了多少输入以获取第100对输出,然后访问其第二个组件的第500个元素?& #34 ;.这些问题是完全合法的,一般来说很难回答。

但是,您的代码永远不会要求完整的输入列表输出有限的输出部分。这使得它变得懒惰&#34;。

为了完整性,让我展示一个懒惰函数:

foreach($questions['questions'] as $question) {

    $questionObject = Question::create([
      'external_id' => $question['id'],
      'text' => $question['question_text'],
      'type' => $question['question_type'],
      'image' => (array_key_exists('question_image', $question)) ?
          $question['question_image'] : ''
    ]);

}

上面,在产生输出列表的头部之前,需要递归调用的结果。这将在生成输出的任何部分之前要求整个输入。