假设我有这个函数:(Haskell 语法)
f x = (x,x)
这个函数执行的工作量(计算量)是多少?
一开始我认为它显然是常数,但如果 x
的类型不是有限的,也就是说,x
可以占用任意数量的内存,那么我们还必须考虑复制 x
所需的工作量,对吗?
这让我相信函数执行的工作实际上与输入的大小成线性关系。
这不是针对作业的问题,而是当我需要定义函数的工作量时遇到的问题:
f x = [x]
我认为这个问题有相似的情况。
假设我有这个函数:(Haskell 语法)
f x = (x,x)
这个函数执行的工作量(计算量)是多少?
一开始我认为它显然是常数,但如果 x
的类型不是有限的,也就是说,x
可以占用任意数量的内存,那么我们还必须考虑复制 x
所需的工作量,对吗?
这让我相信函数执行的工作实际上与输入的大小成线性关系。
这不是针对作业的问题,而是当我需要定义函数的工作量时遇到的问题:
f x = [x]
我认为这个问题有相似的情况。
非常不正式地说,所做的工作取决于您的语言的操作语义。Haskell是惰性的,所以您只需支付以下固定因素:
x
的指针推送到堆栈上(,)
分配一个堆单元(,)
应用于其参数完成。 O(1) 工作量,当调用者查看 f
的结果时执行。
现在,如果您查看 (,)
的内部,您将触发进一步的评估--这项工作取决于评估 x
本身的工作。由于在Haskell中对 x
的引用是共享的,因此您仅评估它一次。
因此,如果完全评估结果,则Haskell中的工作量为 O(work of x)。您的函数 f
仅添加了定值因素。
(,)
是一个 封装 元组,这意味着它仅仅是一个保存指针的结构。如果你使用的语言中 (,)
创建的是 非封装 元组,那么如果 x
大于一个指针,将需要额外的工作来复制 x
到两个插槽中,并且该工作量随着 x
的大小而增加。GHC 提供了带有各种限制的非封装元组 (#,#)
。 - Dan Burton
(x,x)
这样的表达式可能会触发对x
的两次求值,这取决于单态限制是否生效。例如,请参阅最近的博客文章:[http://ics.p.lodz.pl/~stolarek/blog/2012/05/towards-understanding-haskells-monomorphism-restriction/](了解Haskell的单态限制)。 - ErikR