对不起,我无法找到在标题中更清楚地表达问题的方法,但基本上就是这样:几乎所有函数式语言都有允许你通过尾部处理变量参数列表的结构递归,就像在这个Erlang-ish伪代码中总结了一个数字列表:
sumup(0,A) -> A.
sumup(N,A) -> sumup(N) + A.
然而,函数式语言对我的一大吸引力是它们固有的并行性。即使诸如总结一个数字列表之类的问题显然是可以并行化的,并且几乎肯定会通过分而治之的方式最有效地处理,但我并不知道语言功能使这成为一种自然的编程方式。实际上,除非语言具有允许根据函数读取参数数量并根据索引检索参数的功能,否则我不会看到如何这样做。是否有任何功能语言具有鼓励分而治之的编程的功能?
答案 0 :(得分:7)
是否有任何功能语言具有鼓励分而治之的编程功能?
是:能够在库中创建新的高阶函数。
无论如何,列表中最重要的一个这样的函数是foldr
,当应用于关联运算符时,它原则上可以并行化,尽管在实践中很少这样做。为什么?因为foldr
是围绕顺序数据流设计的。
功能语言的优点在于,一旦认识到这个问题,我们就可以解决问题,而不是通过引入新的语言功能,而是通过更加智能地使用我们已有的功能。要了解如何,请查看Guy Steele's talk from August 2009,在那里他解释了为什么foldr
不是并行函数式编程的正确库函数,他建议
这些都旨在支持分而治之的编程。
我发现这个演讲非常令人兴奋的是没有必要引入新的语言功能来支持“原生”的分而治之的编程。这足以取得我们已经存在的原语有和使用它们来设计更好的图书馆。
如果您可以访问ACM数字图书馆,您可以看到Guy的演讲视频Organizing Functional Code For Parallel Execution,或者当Ben Karel指出时,您可以在Vimeo上看到video taken by Malcom Wallace。
答案 1 :(得分:4)
自动并行性并不像看起来那么容易。这样做的问题在于,如果分区是自动完成的,则存在过度分区(太多分区)的风险,这会增加太多开销或分区不足,这将无法正确推进CPU中的所有核心。 静态地(即在编译时)解决这个问题非常困难,这就是为什么通常需要开发人员注释 where 来并行化。
示例:
Haskell有par
combinator,它用作创建 spark 的注释,这个计算在CPU核心可用时变成一个线程。
Data Parallel Haskell:定义一个并行数组数据类型以允许更隐式的并行化方式,但它似乎以某些限制为代价,并且仍然是实验代码。
(免责声明:我不是Haskell开发人员)
Task Parallel Library in .NET: 可以自动并行化数据,也可以实现自己的Partitioner。 您仍然需要了解并行化的工作原理,或者您最终会得到over- or underpartitioning。 Reed Corpsey有great series of articles on the TPL and PLINQ。
DryadLINQ以PLINQ为基础,增加了自动分布式计算。
这些都不是该语言的原生语言,但它们是紧密集成的。甚至有PLINQ integration module for F#。
答案 2 :(得分:2)
看一下Manticore,它的前任NESL,以及它的兄弟ZPL。所有这些都是至少部分功能语言,具有并行结构,用于一次操作数据结构的整个内容。
答案 3 :(得分:1)
我不熟悉任何具有分而治之类型模式的语言。正如你所说,很难想象你如何指定类似的东西。
如果没有全新的符号,我认为像partition
这样的经典函数是我们能做的最好的。
答案 4 :(得分:0)
这种东西在Ruby中很容易指定。在此示例中,我们将范围拆分为三个组,并在每个组上分配一个sum方法。然后我们对得到的部分和求和。您可以非常轻松地扩展它以使其成为多线程。
(1..10).each_slice(3).map{ |x| x.inject :+ }.inject(:+)
此示例与您的示例略有不同,但显示了原则。