【问题标题】:Computational Complexity of Higher Order Functions?高阶函数的计算复杂度?
【发布时间】:2015-05-24 08:02:18
【问题描述】:

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

map (+) list

map (complex_function) list

【问题讨论】:

  • 一个很好的例子可能是filter isPrime [1..n]

标签: haskell functional-programming complexity-theory higher-order-functions


【解决方案1】:

几乎在所有情况下,当高阶函数的文档说明其复杂度为 O(f(n)) 时,这是假设高阶函数具有恒定的时间复杂度 O(1)。此外,n 的确切含义可能会有所不同,但如果没有明确说明,则应从上下文中清楚:例如列表的长度、集合/映射中元素/关联的数量等等。

假设我们有一个称为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 的复杂性。

但是,可能有一些方法可以利用参数性来恢复更有用的界限。例如,如果我们的 order 函数有类型

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

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

但是,我不知道如何形式化和证明上述概述的主张。很有可能有一些关于这个主题的研究论文。

【讨论】:

  • 我从来没有想过使用参数化从无中生有的时间限制。不过我认为它的实用性相当有限——无论你做什么给函数提供的任何信息都可以提供给忙碌的海狸之类的。
【解决方案2】:

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

n 是什么?

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

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

(脚注:是的,您可以将一个函数传递给mapfilter,当它处理更多元素时,它实际上会执行更多工作,但这很无趣,而且我正在尝试在这里制作。)

【讨论】:

  • 你确定那个脚注吗?我不明白你怎么能做这样的事情,虽然traversefilterM 肯定可以。我错过了什么吗?
  • @dfeuer:我想是的?只需将您看到的每个元素都附加到一个数组中,然后在执行此操作之前对整个数组执行额外的虚拟扫描。
  • 如果您使用的是unsafePerformIO,则只能通过传递给映射或过滤器的函数来执行此操作
【解决方案3】:

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

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

公牛。符号逻辑 3 (1997), no. 4, 469--486。 http://projecteuclid.org/euclid.bsl/1182353537.

【讨论】:

  • 总结一些要点(尤其是关于问题)是个好主意,因为这是一个非现场链接(此处不鼓励仅链接的答案),并且还需要订阅查看。
猜你喜欢
  • 1970-01-01
  • 2020-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-04
  • 2015-07-25
相关资源
最近更新 更多