【问题标题】:Is `map` in Haskell lazy?Haskell中的`map`是懒惰的吗?
【发布时间】:2021-08-01 09:18:27
【问题描述】:

我一直在研究 Graham Hutton 在 Haskell 中的编程。它指出

函数map 将函数应用于列表的所有元素

好的,有道理。当然符合我对其他语言地图的了解。

其中一个练习是实现all :: (a -> Bool) -> [a] -> Bool

有时,如果不懒惰地完成,天真的实现可能会无限循环。例如all (<10) [1..]。所以我的第一个实现是:

all p []       = True
all p (x:xs)   | not (p x) = False
               | otherwise = all' p xs

但后来我考虑尝试使用 mapand 的函数组合来看看 Haskell 中的非终止程序会做什么:

all' :: (a -> Bool) -> [a] -> Bool
all' p = and . map p

令我惊讶的是,all' (<10) [1..] 很快就返回了False。我实际上希望map 在应用and 之前尝试创建一个无限列表——类似于and [p x | x <- xs, p x]

这种终止行为意味着map 实际上正在创建类似于and 正在处理的流的东西。 map 实际上是懒惰的(因此描述是错误的)还是我在第二次实现中误解了其他内容?

【问题讨论】:

  • 列表理解也是惰性的,所以and [p x | x <- xs] 将在列表中有False 的那一刻终止。如果您使用and [p x | x <- xs, p x],则不会在无限列表上终止,因为您使用p x 进行过滤,因此只会在列表中返回Trues。
  • 在 Haskell 中,你应该假设一切都是惰性的,除非有其他证据/文档。
  • @LouisWasserman 很高兴知道。很棒的提示 - 谢谢。

标签: haskell lazy-evaluation higher-order-functions


【解决方案1】:

map 实际上是懒惰(因此描述错误)还是我在第二次实现中误解了其他内容?

map 很懒惰。它不会急切地将功能应用于每个项目。事实上,所有表达式都是惰性的,因为除非需要该值,否则 map f x 仍然是 map f xs

如果我们评估map f xs,并且我们需要例如第三个元素,如果我们对第一个元素的不感兴趣,它将无法确定f x<sub>1</sub>

列表推导也是惰性的。事实上,如果我们与:

and [<strong>p x</strong> | x &lt;- xs]

它将从xs 中的x 中的一项具有Falsep x 的那一刻起终止。然而,如果你添加一个过滤器p x,它只会发出Trues,确实:

[<strong>p x</strong> | x &lt;- xs, <b>p x</b>]

只会产生True,因为我们已经过滤了p x应该是True的事实,并且Trues的无限列表中的and永远不会终止,因为and 将继续寻找False 值。

【讨论】:

  • 非常有用。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-06
  • 2015-09-06
  • 2018-01-28
  • 1970-01-01
  • 2015-04-02
  • 2017-01-21
  • 2016-12-14
相关资源
最近更新 更多