一些数据结构是否比其他数据结构更适合函数式编程?

时间:2009-03-01 02:51:36

标签: data-structures functional-programming immutability

Real World Haskell中,有一个标题为“没有数组或哈希表的生命”的部分,其中作者建议列表和树在函数式编程中是首选,而数组或哈希表可能用于代替命令式计划。

这是有道理的,因为在创建新列表或树时,重用部分(不可变)列表或树要比使用数组更容易。

所以我的问题是:

  • 功能和命令式编程之间的数据结构的使用模式是否真的有很大差异?
  • 如果是,这是一个问题吗?
  • 如果您确实需要某个应用程序的哈希表怎么办?您是否只是吞下了修改所产生的额外费用?

9 个答案:

答案 0 :(得分:14)

本书Purely Functional Data Structures深入介绍了您的问题,包括主要在ML中的理论和实现的完美组合 - 附录还包含Haskell实现,因此您应该能够跟随一些额外的页面转换。如果你真的对你的问题的彻底回答感兴趣,这是一个非常好的(虽然部分困难)阅读。话虽如此,我认为ephemient给出了一个极好的简短答案。

编辑:Steven Huwig提供了link论文,该书开篇为。虽然我没有读过它,但是缺少的唯一重要的东西(从目录中判断)是Haskell的实现。

答案 1 :(得分:12)

作为一名多年来一直在做OO的人,最近在Haskell建立了一个需要大量速度的大型项目(实时自动化期权交易系统):

  • 功能和命令式编程之间的数据结构的使用模式是否真的有很大差异?

如果你在谈论Haskell,是的,非常如此。然而,很大一部分是由于纯度;在更常使用可变数据的其他函数语言中,差异稍微小一些。也就是说,正如其他人所指出的那样,递归代码和结构在所有或几乎所有函数语言中使用得更多。

  • 如果是,这是一个问题吗?

除了不得不花一些时间学习新的工作方式之外,它不适合我。特别是,性能肯定不是问题:例如,我正在开发的系统运行速度比以前的Java实现快得多。

  • 如果您确实需要某个应用程序的哈希表怎么办?您是否只是吞下了修改所产生的额外费用?

通常问题不在于“你真的需要一个哈希表”,而是你需要在某些给定的时间限制内访问某些数据(这可能是“在某些给定硬件上尽可能快”。) 。为此,你环顾四周,做你需要做的事情。如果这包括引入可变性,我没有看到它的大问题,你可以在Haskell中做到这一点,尽管它可能不像在其他语言中那样方便。但是请记住,如果你有这种性质的问题,它肯定不会那么简单,“使用通用哈希表,你就完成了。”特定硬件平台上特定功能的极高性能总是需要大量工作,通常不仅仅是一些技巧。在我看来,将一种语言实现优先于另一种语言只是因为它有一些特殊的东西比其他语言更好,在我看来,这是一种相当简单的软件工程方法,不太可能产生良好的结果。

答案 2 :(得分:11)

  • 是。通常,元组,列表和部分评估的函数是函数式编程语言中非常常见的数据结构。可变数据结构(如数组和(实际)哈希表)的使用要少得多,因为它们不适合Haskell。 SML(也是功能的,但不是懒惰的)可以比Haskell更自然地使用数组,但是列表仍然更常见,因为它们很好地映射到递归算法。
  • 我不知道如何回答这个问题。谁的问题?
  • 存在关联数组(“哈希表”等价物)的实现,即使在不同的更新之后,它们也可以继续共享其大部分底层结构。我相信GHC的Data.Map会这样做;另外,Edison有很多懒惰/功能友好的数据结构。

答案 3 :(得分:4)

Chris Okasaki的论文Purely Functional Data Structures可在线免费获取。它涵盖了不可变持久数据表示的许多不同策略。

就真正需要哈希表而言,当你搜索一百万个元素时,考虑O(lg n)查找的速度只是O(1)查找速度的二十倍。

答案 4 :(得分:4)

是的,使用模式有很大不同,但不是没有问题。如果你想要一个哈希表,你通常意味着你想要一个带有字符串键和快速访问的有限映射。 Bentley和Sedgewick的ternary search trees是纯粹的功能,至少在某些情况下,它们优于哈希表。

如上所述,Chris Okasaki关于纯功能数据结构的书非常好。

答案 5 :(得分:1)

功能程序倾向于更加强调递归。反过来,这表明使用递归算法和递归数据结构。列表和树都是递归结构(列表中的“下一个”链接是另一个列表,树节点的子节点都是树)。

如果您正在考虑算法的额外费用,您可能需要重新考虑。为什么哈希表(非递归算法的O(1))会产生额外费用?使用它有什么好处,而不是树或列表?

答案 6 :(得分:1)

  
      
  • 数据的使用模式确实存在显着差异   功能与...之间的结构   命令式编程?
  •   

大,巨大,昼夜 - 主要是因为功能性编程不能容忍副作用。

  
      
  • 如果是,这是一个问题吗?
  •   

问题在于,由于并行化变得更加必要,因此无法保持效率的命令式范例 - 这些语言的唯一出路是摆脱副作用,但随后它们将成为破坏的函数式语言 - 但随后,当有一些非常好的,有效的功能语言时,我为什么要打扰它们呢?此外,函数式语言的语义更容易控制,因此功能程序可以被证明是正确的,而它们的C ++对应物则不能(无论如何)。因此,许多形式验证工具都基于函数式语言 - 例如,ACL2基于常见的lisp,Cryptol基于Haskell。由于正式验证是未来功能语言的浪潮,可以更好地与这些工具集成。简而言之,说再见C,C ++等 - 好的证据!很久以前,有人应该给他们带来30分6分。

  
      
  • 如果您确实需要某个应用程序的哈希表怎么办?你呢   简单地吞下额外的费用   因修改而招致?
  •   

未来的浪潮是这样的:你用函数编写函数式编程 指定哈希表 - 您使用的语言是cryptol。当你是 完成并证明您的程序可以按下按钮然后弹出 一个有效的版本,如果确定了哈希表,则使用哈希表 最好的用法。

答案 7 :(得分:0)

是的,主要区别在于数据的不变性,包括代码(参见高阶函数)。有关常见数据类型和用法的列表,请参阅Purely Functional上的Wikipedia页面。它是否有问题取决于你如何看待它。如果函数语言符合您正在处理的任务类型,则在函数式语言中编程有许多优点。哈希表是一种关联数组,但不是你想要在函数式语言中使用的那个,因为你必须对插入进行重新编写,而没有数组的性能很差。相反,请尝试使用Haskell implementation of Data.Map作为关联数组。

答案 8 :(得分:0)

就功能语言中的哈希表而言:由于上面提到了ACL2,我会注意到ACL2有一个“哈希缺点”库提供了基本上是关联列表语义但具有性能的逻辑故事。哈希表(例如,您可以使用hons-get在表中查找值)。如果您有兴趣,请查看ACL2用户手册中的“hons”主题。