高阶函数的计算复杂度?

Computational Complexity of Higher Order Functions?

Map 和 filter 似乎是线性 O(n) 因为它们只需要遍历一次列表,但是它们的复杂度是否受传递函数的影响?例如下面的两个例子是同一个顺序吗?

map (+) list

map (complex_function) list

您似乎有一个(常见的)误解,认为复杂性是 n 的函数。

什么是 n

n 只是衡量您的输入的一个参数。它可能不足以(甚至是必要的)统计数据来描述您的输入——您可能需要其他变量来准确描述您输入的复杂性。

所以,mapfiltern中是线性的。它们对其他变量的依赖取决于您传递的函数,但它们对 n 的依赖通常不会。

(脚注:是的,您 可以 将一个函数传递给 mapfilter,当它处理更多元素时实际上执行更多工作,但那是无趣而且离题了。)

在几乎所有情况下,当高阶函数的文档声明其复杂度为 O(f(n)) 时,这是假设高阶函数具有常数时间复杂度 O(1)。此外,n 的确切含义可能会有所不同,但如果没有明确说明,从上下文中应该很清楚:例如列表的长度,elements/associations 在 set/map 中的数量,等等。

假设我们有一个称为 g h ... 的高阶函数 g,其中 h 是一个函数,... 是一阶数据。没有关于高阶函数 g 的任何其他信息,如果文档指出它是 O(f(n)),您可以获得更现实的 O(f(n)) * CostH 的最坏情况界限,其中 CostH 表示调用 H 一次的成本。

当然,CostH 也将取决于哪些参数开始传递给 h:在这里,我们所知道的是这些参数是在 O(f(n)) 时间内构建的。很难对 h 的参数大小给出一个有用的一般界限,因为例如,如果 h 将树作为输入,那么您可以在短时间内构建一个非常大的树:

foo :: Int -> Tree ()
foo 0 = Tree []
foo m = Tree [t,t] where t = foo (m-1)

上面构建的树在 m 时间内有 2^m 个叶子(感谢分享)。这可以适应 3^mb^m 微不足道地保持 b*m 复杂性。

但是,可能有一些方法可以利用参数化来恢复更有用的边界。例如,如果我们的订单函数有 type

g :: (a -> Int) -> [a] -> Int

然后我们知道 g h [...] 只能使用从列表中获取的参数调用h。同样,库函数调用 sortBy h [...] 只能使用 h 来比较所提供列表中的两个元素。

但是我不知道如何形式化和证明上面的草图声明。很可能有一些关于该主题的研究论文。

有关复杂性和高阶函数的一些背景知识,例如,参见

霍夫曼,马丁。范畴论语义学在复杂性表征中的应用 类 使用高阶函数代数。

牛。符号逻辑 3 (1997),没有。 4、469--486。 https://doi.org/10.2307/421100