功能编程中是否存在“算法”?

时间:2014-09-19 18:34:21

标签: algorithm functional-programming

被要求记录"算法"是否毫无意义。您的软件(例如,在设计规范中)是否以功能范例实现?每当我想到技术文档中的算法时,我都会想到一个带有一系列连续步骤的while循环。

查看算法的非正式字典含义:

  

在数学和计算机科学中,算法是用于计算的逐步程序

短语"一步一步"似乎违背了函数式编程的范式(正如我所理解的那样),因为与命令式程序相比,函数式程序在其假设机器中没有时间意识。这个论点是否正确?或懒惰评估是否强制执行一个隐含的时间组件,使其逐步“#34;?

编辑 - 这么多好的答案,选择最佳答案对我来说是不公平的:(感谢所有观点,他们都做出了很好的观察。

4 个答案:

答案 0 :(得分:15)

是的,算法仍然存在于函数式语言中,尽管它们看起来并不总是与命令式算法相同。

而不是使用" time"的隐含概念。基于状态到模型步骤,函数式语言使用组合数据转换来完成。作为一个非常好的示例,您可以将堆排序分为两部分:从列表转换为堆,然后从堆转换为列表。

您可以使用递归非常自然地对逐步逻辑进行建模,或者更好的是,使用现有的高阶函数来捕获您可以执行的各种计算。编写这些现有作品可能就是我真正称之为"功能风格":您可以将您的算法表示为展开,然后是地图,然后是折叠。

懒惰通过模糊"数据结构和#34;之间的界限使这更有趣。和"算法"。像列表一样的惰性数据结构永远不会完全存在于内存中。这意味着您可以编写构建大型中间数据结构的函数,而无需实际使用所有空间或牺牲渐近性能。作为一个简单的例子,考虑factorial的这个定义(是的,这是陈词滥调,但我无法做出更好的事情:/):

factorial n = product [1..n]

这有两个组成部分:首先,我们生成一个从1n的列表,然后我们通过乘以(product)来折叠它。但是,由于懒惰,列表永远不会完全存在于内存中!我们在product的每个步骤中评估尽可能多的生成函数,垃圾收集器回收旧单元格,因为我们已经完成了它们。因此,即使看起来喜欢它需要O(n)内存,它实际上也会被O(1)所取代。 (好吧,假设数字都需要O(1)个记忆。)

在这种情况下,"结构"算法的步骤顺序由列表结构提供。这里的列表更接近于for循环而不是实际列表!

因此在函数式编程中,我们可以通过几种不同的方式将算法创建为一系列步骤:通过直接递归,通过组合转换(可能基于常见的高阶函数)或通过懒惰地创建和使用中间数据结构。

答案 1 :(得分:7)

我认为你可能误解了函数式编程范式。

无论您使用的是函数式语言(Lisp,ML,Haskell)还是命令式/过程式(C / Java / Python),您都要指定操作及其顺序(有时可能未指定顺序,但这是一个问题)。

功能范例对你可以做的事情设置了某些限制(例如,没有副作用),这使得更容易推理代码(并且顺便说一句,更容易编写“足够智能编译器”)。

考虑,例如,阶乘的功能实现:

(defun ! (n)
  (if (zerop n)
      1
      (* n (! (1- n)))))

人们很容易看到执行的顺序:1 * 2 * 3 * .... * n以及存在的事实 参数n-1的乘法和减法n

计算机科学最重要的部分是要记住,语言只是与计算机交谈的手段。 CS关于计算机只不过天文学是关于望远镜的,算法是在抽象(图灵)机器上执行的,由我们面前的实际盒子模拟。

答案 2 :(得分:6)

不,我认为如果你在功能上解决了问题并且你必须解决它,你提出的是两个独立的算法。每个都是算法。一种是功能算法,一种是命令式算法。有许多关于函数式编程语言算法的书籍。

在这里,你似乎陷入了技术/语义。如果要求您记录算法以解决问题,那么任何要求您的人都想知道您是如何解决问题的。即使它的功能,也会有一系列步骤来达到解决方案(即使是所有的懒惰评估)。如果您可以编写代码来达到解决方案,那么您可以用伪代码编写代码,这意味着就我而言,您可以根据算法编写代码。

而且,既然你似乎对这里的定义非常感兴趣,我会以你的方式提出一个问题来证明我的观点。编程语言,无论是功能性的还是命令式的,最终都在机器上运行。对?必须告知您的计算机要运行低级指令的分步过程。如果该陈述成立,那么每个高级计算机程序都可以用它们的低级指令来描述。因此,每个程序,无论是功能的还是命令的,都可以用算法来描述。如果您似乎无法找到描述高级算法的方法,那么输出字节码/汇编并根据这些说明解释您的算法

答案 3 :(得分:3)

考虑这个功能方案示例:

(define (make-list num)
  (let loop ((x num) (acc '()))
    (if (zero? x)
        acc
        (loop (- x 1) (cons x acc)))))

(make-list 5)            ; dumb compilers might do this
(display (make-list 10)) ; force making a list (because we display it)

您的逻辑make-list不会被视为算法,因为它不会按步骤进行计算,但这是真的吗?

Scheme非常渴望并按顺序进行计算。即使使用惰性语言,所有内容都会逐步进行计算,直到您拥有一个值。不同之处在于,惰性语言按依赖顺序进行计算,而不是按照指令的顺序进行计算。

函数式语言的底层机器是一个寄存器机器,所以很难避免你漂亮的函数程序实际上成为改变寄存器和内存的汇编指令。因此,函数式语言(或惰性语言)只是一种易于编写代码的抽象。