函数式编程与声明性编程和命令式编程

时间:2012-06-07 04:32:29

标签: terminology

我已经习惯了命令式编程,这是告诉计算机逐步执行程序以获得最终结果的常用方法。另一方面,声明性编程只是传递输入并期望输出而不说明过程如何完成。我很困惑的是功能编程。我知道函数式编程是一种编程范式,它将计算视为数学函数的评估,避免使用状态和可变数据,而不是一种声明性语言。但是,我仍然不能理解它是如何工作的。

让我们举一个执行斐波那契数字的例子。

命令式编程:

#include<stdio.h> 
#include<conio.h> 
main() 
{ 
  int n,i,c,a=0,b=1; 
  printf("Enter Fibonacci series of nth term : "); 
  scanf("%d",&n); 
  printf("%d %d ",a,b); 
  for(i=0;i<=(n-3);i++) 
  { 
    c=a+b; 
    a=b; 
    b=c;    
  } 
  printf("%d ",c);
  getch(); 
} 

声明性编程:

Give the nth number and it will return the value of the nth number

功能计划如何运作?

如果我的定义错了,请加以纠正。请随时发表评论..

6 个答案:

答案 0 :(得分:44)

上面的声明性编程示例不是一个实际的程序,所以它不是一个很好的例子。

主要区别在于命令式和声明式。功能是一种特殊的声明。

C,C ++,Java,Javascript,BASIC,Python,Ruby和大多数其他编程语言强制性。通常情况下,如果显式循环(for,while,repeat)在每个循环中使用显式赋值操作更改变量,那么这是必要的。

SQL和XSLT是声明性编程的两个着名示例。标记语言(如HTML和CSS)也是声明性的,尽管它们通常不足以描述任意算法。

这是一个示例计算(按性别划分收入,来自合适的数据源),首先用命令式语言(Javascript)编写,然后用声明性语言(SQL)编写。

命令式编程

var income_m = 0, income_f = 0;
for (var i = 0; i < income_list.length; i++) {
    if (income_list[i].gender == 'M')
        income_m += income_list[i].income;
    else
        income_f += income_list[i].income;
}

注意:

  • 显式初始化包含运行总计的变量;
  • 显式循环数据,修改控制变量(i)和每次迭代的运行总计;
  • 条件(if s)仅用于在每次迭代时选择代码路径

声明性编程

select gender, sum(income)
from income_list
group by gender;

注意:

  • 包含运行总计的内存单元格是您声明所需的输出暗示;
  • CPU需要执行的任何循环(例如,在income_list表上)由您声明的输出暗示以及源数据的结构;
  • 条件(例如,SQL中的case)以功能方式用于根据输入值指定所需的输出值,而不是选择代码路径。

功能编程

正如我上面提到的,SQL的case功能编程方式的一个很好的例子,它是声明式编程的一个受限子集,其中所需的计算由撰写功能。

函数是接受输入和返回输出的事物(例如casesum() ......)

组合意味着链接两个或多个一起指定一个输出作为输入到下一个(通常是在另一个内部写入)。最后整个组合,仍然是它本身就是一个很大的功能,应用于可用的输入以获得所需的输出。

在此代码段中,我通过组合功能 sum()case来声明我想要的输出。这称为函数式编程:

select 
    sum(case when some_flag = 'X' then some_column
        else some_other_column end)
from
    ...

如果两个或多个函数的组合及其对输入数据的应用是给定语言中唯一可用的构造,则该语言被称为纯函数。在这些语言中,您会注意到完全没有循环,变量赋值和其他典型命令性语句。


编辑:我建议观看一些 Anjana Vakil 关于Javascript函数式编程的讨论,以便更好地了解它的内容。

答案 1 :(得分:4)

erroneous oversimplification to claim that命令式编程与声明式编程的区别在于错误地假设后者缺乏排序。

不会阻止纯函数式编程表达顺序和实现,而是不能在操作语义级别表达随机意外顺序。它还具有“不要重复自己”(DRY)的优点,这是一种陈述式的形式(见下文)。

然而,纯函数式编程并不能保证声明性的高级语义。为此,您需要应用correct definition of declarative vs. imperative

答案 2 :(得分:2)

想想c过滤器。你从stdin读取并写入stdout的地方。代码可能是必要的,但thr程序就像一个函数一样使用。假设你有一个程序'功能,然后管道到它:

cat foo  |function |tee bar

将通过函数过滤foo的内容,然后通过过滤器 tee 写入stdout并创建 bar 。 也可以考虑 grep awk 两者中的迭代器是隐含的,它们像函数一样使用。

答案 3 :(得分:1)

我在Pro XAML with C#中找到了另一个有用的解释:

关于声明式

  

在声明式编程中,源代码以以下方式编写:   很少或根本没有表达出代码的预期结果   在实际的实现上。

当务之急

  

命令式编程与声明式编程相反。如果   声明式编程可以认为是声明了什么   期望的结果是,命令式编程可以看作是写作   代表如何实现   预期的结果。

答案 4 :(得分:0)

处理将输入转换为输出。计算机程序是硬件操作的列表,这些程序在执行时将根据输入的任何内容执行这些过程。并非所有的计算机语言都可用于编写生成过程的程序。某些计算机语言只是描述数据之间的关系,而您的问题用恰当的措辞来专门询问定义流程的编程语言。

原始的命令性语言(例如Assembly)是根据机器操作编写的。原语是move-data-into-register-x, add-register-x-to-y-store-in-y…命令性语言根据某些特定数据机如何实现过程来描述过程。

说明性语言(*功能性语言是它们的子集)是根据非机器原语编写的。数学是一种声明性语言,其一些原语就是数字公理。声明性语言更清晰地描述了流程,因为它们根据原始问题域表达了转换。

例如1。Fib(0), Fib(1)=1, Fib(n) = n-1 + n-2

例如2。x = [x in 1..100 if x mod 3 != 0]

*功能语言一词是在计算机程序员主要编写机器指令时创造的。现在,无副作用程序和列表表达式等功能语言概念已成为主流命令性语言的一部分。因此,功能性语言与声明性语言的区别不大。

声明性程序显然不能映射到机器指令。纯声明性语言的好例子是数学,Lisp,Prolog和Wolfram Alpha。 HTML,SQL,XSLT和SDLang是定义数据关系的语言,它们不是您要询问的那种编程语言。您不会使用HTML,SQL,XSLT或SDLang创建计算机进程。

这些天来,现代高级语言实际上是命令术语和声明性范式的混合体,因为这些术语最初是被创造出来的。好的高级类设计,几乎可以通过方法名称来描述数据发生了什么。因此,这些术语几乎与国际海事组织不合时宜。

答案 5 :(得分:0)

在函数式编程中,我们使用纯函数构建不可变的程序。这就是纯函数:(我提到纯函数是因为函数式编程基于纯函数)

  • 它仅取决于提供的输入,而不取决于在评估期间或调用之间可能发生变化的任何隐藏或外部状态。
  • 它不会造成超出其​​范围的更改,例如修改全局对象或通过引用传递的参数。

对于纯函数的简短描述,函数式编程是指对纯函数进行声明式求值以创建 通过避免外部可观察到的副作用来实现不可变的程序。

简单地说,函数式编程是声明式编程范式,它是一种表达一组操作的范式,而不揭示它们是如何实现的或数据如何流经它们。命令式编程处理一个 计算机程序只是一系列自上而下的语句,它改变了 系统状态以计算结果。

这是命令式编程的一个例子:我们遍历一个数组,计算每个元素的平方,然后将新值存储在同一个数组中。我们正在改变数组。另外,这个循环是不可重用的,对于每个不同的数组,我们会定义一个新的for循环。

var array= [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 for(let i= 0; i < array.length; i++) {
     array[i]=Math.pow(array[i], 2);
  }
array; //-> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

在 javascript 中我会使用 Array.map()

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map((i)=>i*i)

在这个方法中,我们不知道 Array.map() 是如何实现的。程序的定义与评估分开。更重要的是,这段代码不会改变原始数组,而是创建了一个新数组

声明式编程的另一个很好的例子是编写 SQL 查询。我们只是写了一个简单的 SQL 语句从数据库中拉取数据,但我们不知道幕后发生了什么,所有的魔法都从我们身上抽象出来了。