功能和命令式编程语言有什么区别?

Swa*_*wal 136 oop functional-programming

大多数主流语言,包括面向对象编程(OOP)语言,如C#,Visual Basic,C++和Java,主要用于支持命令式(过程式)编程,而Haskell/gofer类似语言纯粹是功能性的.任何人都可以详细说明这两种编程方式之间的区别吗?

我知道这取决于用户要求选择编程方式,但为什么建议学习函数式编程语言?

Ing*_*ngo 215

这是区别:

势在必行:

  • 开始
  • 打开你的鞋码9 1/2.
  • 在口袋里腾出空间以保持钥匙的阵列[7].
  • 将钥匙放在房间里,放入口袋里的钥匙.
  • 进入车库.
  • 打开车库.
  • 输入汽车.

......等等......

  • 把牛奶放入冰箱.
  • 停止.

声明性的,其中function是子类别:

  • 牛奶是一种健康的饮料,除非你有消化乳糖的问题.
  • 通常,人们将牛奶储存在冰箱中.
  • 冰箱是一种可以让物品保持凉爽的盒子.
  • 商店是销售商品的地方.
  • "卖"是指用钱换货.
  • 此外,为事物换钱也称为"购买".

......等等......

  • 确保我们在冰箱里放牛奶(当我们需要它时 - 用于懒惰的功能语言).

简介:在命令式语言中,您告诉计算机如何更改其内存中的位,字节和单词以及顺序.在功能性方面,我们告诉计算机什么是事物,行为等.例如,我们说阶乘为0是1,而每个其他自然数的阶乘是该数字与其前身的阶乘的乘积.我们不说:要计算n的阶乘,保留一个内存区域并在那里存储1,然后将该内存区域中的数字乘以数字2到n,并将结果存储在同一个地方,最后,内存区域将包含阶乘.

  • @Igno,和Subroto一样,我真的不明白你的解释.看起来你写的东西可以概括为:需要答案......得到答案.它似乎忽略了重要的一点是如何.我不明白你怎么能隐藏用户的那部分,在某些时候有人必须知道它是如何完成的......你不能永远把这个向导留在幕后. (8认同)
  • 令人费解的解释. (6认同)
  • @Ingo这是有史以来最清晰的解释. (5认同)
  • 我喜欢你的解释@Igno,但我还不清楚.在Declarative中,即使你只是告诉**东西,但你仍需要更改位并对机器中的状态进行更改才能正确进行.这让我很困惑,不知怎样,Declarative类似于Procedural Programming*(比如C函数)*,并且它们内部仍然存在很大的差异.不是*C函数*与函数式编程中的函数*相同*(在机器级别上)? (3认同)
  • 这不是我理解的函数式编程.我认为函数式编程是从函数中删除隐藏的输入和输出. (3认同)

小智 141

定义: 命令式语言使用一系列语句来确定如何达到某个目标.据说这些语句会改变程序的状态,因为每个程序依次执行.

示例: Java是一种命令式语言.例如,可以创建一个程序来添加一系列数字:

 int total = 0;
 int number1 = 5;
 int number2 = 10;
 int number3 = 15;
 total = number1 + number2 + number3; 
Run Code Online (Sandbox Code Playgroud)

每个语句都会更改程序的状态,从为每个变量赋值到最终添加这些值.使用五个语句的序列,程序被明确告知如何将数字5,10和15一起添加.

函数式语言: 明确创建函数式编程范例,以支持解决问题的纯函数式方法.函数式编程是一种声明式编程.

纯函数的优点: 将函数转换实现为纯函数的主要原因是纯函数是可组合的:即自包含和无状态.这些特性带来许多好处,包括:增加可读性和可维护性.这是因为每个函数都是为了在给定参数的情况下完成特定任务而设计的.该功能不依赖于任何外部状态.

更容易重复开发.由于代码更容易重构,因此设计更改通常更容易实现.例如,假设您编写了一个复杂的转换,然后意识到某些代码在转换中会重复多次.如果您通过纯方法重构,您可以随意调用纯方法而不必担心副作用.

更容易测试和调试.由于纯函数可以更容易地单独测试,因此您可以编写使用典型值,有效边缘情况和无效边缘情况调用纯函数的测试代码.

对于OOP People或Imperative语言:

当你对事物进行固定的操作时,面向对象的语言是很好的,随着代码的发展,你主要添加新东西.这可以通过添加实现现有方法的新类来实现,并且现有类是独立的.

当你有一套固定的东西时,功能语言很好,随着代码的发展,你主要在现有的东西上添加新的操作.这可以通过添加使用现有数据类型计算的新函数来实现,并且现有函数是独立的.

缺点:

这取决于用户选择编程方式的要求,因此只有当用户没有选择正确的方法时才有害.

当进化走错路时,你会遇到问题:

  • 向面向对象的程序添加新操作可能需要编辑许多类定义以添加新方法
  • 在功能程序中添加新类型的东西可能需要编辑许多函数定义来添加新案例.

  • 在这种情况下,纯函数等价于数学函数.相同的输入始终映射到相同的输出.它们也没有任何副作用(除了返回一个或多个值),这意味着编译器可以进行一些很好的优化,并且它可以更容易并行运行函数,因为没有什么可以解决的. (8认同)
  • 这个答案试图澄清什么是函数式编程,但是甚至懒得定义纯函数是什么.我没有看到任何人如何阅读这个答案,并且对于了解声明性和程序性编程之间的区别感到自信. (5认同)
  • 我没有看到文本的明显差异,其中突出显示了每个编程的特征.程序编程的大多数描述可以通过命令式编程文本来交换,反之亦然. (4认同)

old*_*onk 11

大多数现代语言在不同程度上都是命令式和功能性的,但为了更好地理解函数式编程,最好采用像Haskell这样的纯函数式语言的例子,而不是像java/c#这样的函数式语言.我相信通过实例解释总是很容易,所以下面是一个.

函数式编程:计算n即n的阶乘!即nx(n-1)x(n-2)x ... x 2 X 1

-- | Haskell comment goes like
-- | below 2 lines is code to calculate factorial and 3rd is it's execution  

factorial 0 = 1
factorial n = n * factorial (n - 1)
factorial 3

-- | for brevity let's call factorial as f; And x => y shows order execution left to right
-- | above executes as := f(3) as 3 x f(2) => f(2) as 2 x f(1) => f(1) as 1 x f(0) => f(0) as 1  
-- | 3 x (2 x (1 x (1)) = 6
Run Code Online (Sandbox Code Playgroud)

请注意,Haskel允许函数重载到参数值的级别.以下是增加强制程度的命令式代码示例:

//somewhat functional way
function factorial(n) {
  if(n < 1) {
     return 1;
  }
  return n * factorial(n-1);   
}
factorial(3);

//somewhat more imperative way
function imperativeFactor(n) {
  int f = 1
  for(int i = 1; i <= n; i++) {
     f = f * i
  }
  return f;
}
Run Code Online (Sandbox Code Playgroud)

这个读取可以很好地理解命令式代码如何更多地关注部分,机器状态(i for for循环),执行顺序,流控制.

后面的例子大致可以看作java/c#lang代码,第一部分是语言本身的限制,而Haskell则通过值(零)重载函数,因此可以说它不是纯粹的函数式语言,另一方面你可以说它支持功能前卫.在某种程度上.

披露:以上代码都没有经过测试/执行,但希望能够很好地传达这个概念; 我也很感激任何这样的修正评论:)

  • 不应该是“return n * Factorial(n-1);”吗? (2认同)

Jak*_*ler 7

函数式编程是一种声明式编程,它描述了计算的逻辑,完全不再强调执行的顺序.

问题:我想把这个生物从马变成长颈鹿.

  • 加长脖子
  • 加长腿
  • 应用斑点
  • 给这个生物一个黑色的舌头
  • 去掉马尾

每个项目都可以按任何顺序运行,以产生相同的结果.

命令式编程是程序性的.国家和秩序很重要.

问题:我想把车停好.

  1. 注意车库门的初始状态
  2. 在车道上停车
  3. 如果车库门关闭,打开车库门,记住新的状态; 否则继续
  4. 把车拉进车库
  5. 关闭车库门

必须完成每个步骤才能达到预期的结果.在车库门关闭时进入车库会导致车库门破损.

  • 哦,谢谢,我会研究更多。你能不能把问题 1 更新为和问题 2“我想停车”一样,但用函数式编程的方式编写?那么并行性将被排除。 (3认同)
  • 我只看到异步与同步的区别。 (2认同)
  • 什么?函数式语言中的操作顺序仍然很重要。“(x - 1) * 3”与“(x * 3) - 1”不同。作为另一个例子,“fillBasket(emptyBasket(b), items)”与“emptyBasket(fillBasket(b, items))”相比具有不同的效果。 (2认同)

kcr*_*ris 6

//The IMPERATIVE way\nint a = ...\nint b = ...    \n\nint c = 0; //1. there is mutable data\nc = a+b; \xc2\xa0 //2. statements (our +, our =) are used to update existing data (variable c)\n
Run Code Online (Sandbox Code Playgroud)\n

命令式程序 = 更改现有数据的语句序列。

\n

关注什么=我们的变异数据(可修改的值又称为变量)。

\n

链接命令式语句 = 使用过程(和/或 oop)。

\n
\n
//The FUNCTIONAL way\nconst int a = ... //data is always immutable\nconst int b = ... //data is always immutable\n\n//1. declare pure functions; we use statements to create "new" data (the result of our +), but nothing is ever "changed"\nint add(x, y) \n{\n   return x+y; //only depends on inputs; only impact on caller: via "return" value\n} \n\n//2. usage = call functions to get new data\nconst int c = add(a,b); //c can only be assigned (=) once (const)\n
Run Code Online (Sandbox Code Playgroud)\n

一个函数式程序=“解释”如何获取新数据的函数列表。

\n

关注如何=我们的功能add

\n

链接函数“语句”=使用函数组合。

\n
\n

这些基本区别具有深远的影响。

\n

严肃的软件有大量的数据和大量的代码。

\n

因此,相同的数据(变量)被用在代码的多个部分中。

\n

A. 在命令式程序中,该(共享)数据的可变性会导致问题

\n
    \n
  • 代码很难理解/维护(因为数据可以在不同的位置/方式/时刻修改)
  • \n
  • 并行化代码很困难(同时只有一个线程可以改变内存位置),这意味着对同一变量的改变访问必须序列化=开发人员必须编写额外的代码来强制对共享资源进行这种序列化访问,通常通过锁/信号量
  • \n
\n

优点是:数据真正就地修改,不需要复制。(一些性能提升)

\n

B. 另一方面,功能代码使用不可变数据,不存在此类问题。数据是只读的,因此不存在竞争条件。代码可以轻松并行化。结果可以被缓存。更容易理解。

\n

缺点是:为了获得“修改”,数据被大量复制。

\n

另请参阅: https: //en.wikipedia.org/wiki/Referential_transparency

\n

更新:在命令式代码中,状态突变可能随处发生。因此,您的逻辑与变异状态交织在一起,这使得该状态实际上影响您的……逻辑,因此代码变得非常难以理解。遥远的非本地状态可能会以意想不到的方式影响功能。

\n

在函数式方法中,只有局部状态很重要,仅在函数内部。在外部,您可以安全地重用您的函数,因为您知道它始终以相同的方式运行,不需要外部上下文来确定它的功能。编写这样的函数成为一个非常强大的工具,只要函数是纯函数,您就可以获得复杂但可靠的代码。

\n


小智 5

函数式编程是“使用函数编程”,其中函数具有某些预期的数学特性,包括参照透明性。从这些特性出发,进一步的特性流动,特别是由可替代性实现的熟悉的推理步骤,这些步骤导致了数学证明(即证明结果的可信度)。

由此可见,功能程序仅是一种表达。

通过注意命令式程序中表达式不再是参照透明的位置(因此不是用函数和值构建的,并且本身不能成为函数的一部分)的位置,可以轻松地看到两种样式之间的对比。最明显的两个地方是:突变(例如变量)其他副作用非本地控制流(例如例外)

在由功能和值组成的表达形式的程序框架上,构建了语言,概念,“功能模式”,组合器以及各种类型的系统和评估算法的完整实用范例。

按照最极端的定义,几乎所有语言(甚至是C或Java)都可以称为功能性语言,但是通常人们会保留专门具有特定相关抽象性(例如闭包,不变值和句法辅助工具(例如模式匹配))的语言。就使用函数式编程而言,它涉及使用functins并构建代码而没有任何副作用。用来写证明