当参数是列表时,惰性求值如何工作?
Posted
技术标签:
【中文标题】当参数是列表时,惰性求值如何工作?【英文标题】:How does lazy evaluation works when the argument is a list? 【发布时间】:2018-06-18 10:10:46 【问题描述】:据我了解,惰性求值是指参数在传递给函数之前不求值,而只有在实际使用它们的值时才求值。
但在 haskell 教程中,我看到了一个示例。
xs = [1,2,3,4,5,6,7,8]
doubleMe(doubleMe(doubleMe(xs)))
作者说命令式语言可能会通过列表一次并制作副本然后返回它。然后它会再遍历列表两次并返回结果。
但在惰性语言中,它会首先计算
doubleMe(doubleMe(doubleMe(1)))
这将返回一个doubleMe(1)
,即2
。然后是4
,最后是8
。
所以它只会在列表中传递一次,并且仅在您真正需要时才传递。
这让我很困惑。为什么惰性语言不将列表作为一个整体,而是将其拆分?我的意思是我们可以在使用它之前忽略列表或表达式是什么。但是我们在使用它时需要评估整个事物,不是吗?
【问题讨论】:
【参考方案1】:像[1,2,3,4,5,6,7,8]
这样的列表只是语法糖:1:2:3:4:5:6:7:8:[]
。
在这种情况下,列表中的所有值都是数字常量,但我们可以定义另一个更小的列表,如下所示:
1:1+1:[]
所有的 Haskell 列表都是链表,这意味着它们有一个 head 和一个 tail。在上面的例子中,头部是1
,尾部是1+1:[]
。
如果您只想要列表的头部,则没有理由评估列表的其余部分:
(h:_) = 1:1+1:[]
这里,h
指的是1
。如果您只需要 h
,则没有理由评估列表的其余部分 (1+1:[]
)。
这就是列表的惰性求值方式。在需要该值之前,1+1
仍然是 thunk(未计算的表达式)。
【讨论】:
如果我想要整个列表,它将以哪种方式运行?doubleMe(doubleMe(doubleMe(xs)))
或 doubleMe(doubleMe(doubleMe(1)))
doubleMe(doubleMe(doubleMe(2)))
...?
@user8314628 如果您还有其他问题,请在其他地方打开另一个问题,而不是在 cmets 中。
@user8314628 我同意@AJFarmar 的观点,即另一个问题可能是合适的。如果您决定提出一个新问题,我们需要 doubleMe
的定义才能有机会回答该问题。
好的,我认为这将是我最初问题的一部分。
@user8314628 当我不知道doubleMe
是什么或者它是如何实现的时候,我不知道如何回答这个问题。以上是关于当参数是列表时,惰性求值如何工作?的主要内容,如果未能解决你的问题,请参考以下文章