函数式编程的主要特征之一是使用无副作用的函数。然而,这也可以用命令式语言来完成。递归和 lambda 函数(例如 C++0x)也是如此。因此,我想知道命令式编程语言是否是函数式编程语言的超集。
9 回答
我真的不能说它们是否是彼此的子集。不过,我可以说的是(除了真正深奥的语言)它们都是图灵完备的,这意味着最终它们都同样强大,但不一定同样具有表达能力。
一般来说,没有;函数式编程是声明式编程(包括逻辑编程语言,如 Prolog)的一个子集。许多命令式语言从函数式编程语言中借用元素,但仅仅拥有 lambda 或引用透明函数并不能使命令式语言成为函数式语言;函数式编程不仅仅是这些元素。
可以用本机不支持编程范式的语言来实现某种编程范式。例如,它可以在 C 中编写面向对象的代码,但它不是为此目的而设计的。
函数式编程本身就是一种发展良好的编程范式,最好通过 Haskell、LISP 等语言学习。在你学会了它们之后,即使你不经常使用这些语言,你也可以开始在您定期使用的日常语言。
有些人可能喜欢在 Google 上使用C 语言进行面向对象编程
范式是一种做事方式,有两种主要的编程范式:命令式和声明式。某些语言允许混合两种范式这一事实并不意味着一种包含在另一种中,而是这些语言是多范式的。
为了更清楚一点,让我继续你的类比:如果 Lisp 和 OCaml(例如)被认为是函数式语言,并且它们都允许命令式风格......那么命令式应该被认为是函数式的子集吗?
大多数命令式语言没有函数作为一阶类型,而大多数函数式语言。(和 C++ 一样,通过 boost::function。)
通过一阶类型,这意味着值/变量可以是任何类型,一个 int、一个 bool、一个来自 int->bool 的函数。它通常还包括闭包或绑定值,其中您具有相同的功能,但已经填充了一些参数。
恕我直言,这两个是函数式编程的主要内容。
我认为区分范式和语言可能会有所帮助。
对我来说,范式代表“思维方式”(概念和抽象,如函数、对象、递归),而语言提供“做事方式”(语法、变量、评估)。
从理论上讲,所有真正的编程语言都是图灵完备的,并且能够计算任何图灵可计算的函数以及模拟或被通用图灵机模拟。
有趣的是,在某些语言或范式中完成某些任务有多困难,该工具对任务的适用程度如何。甚至康威的生命游戏也是图灵完备的,但这并不让我想用它来编程。
许多语言支持许多范式。C++ 被设计为 C 的面向对象的扩展,但可以在其中编写纯过程代码。
随着时间的推移,一些语言从其他语言或范式中借用/获取特性(只需看看 Java 的演变)。
一些语言,如 Common Lisp,是令人印象深刻的多范式语言。可以在 Lisp 中编写函数式、面向对象或过程式的代码。可以说,面向方面已经是通用 lisp 对象系统的一部分,因此“没什么特别的”。在 Lisp 中,很容易扩展语言本身来做任何你需要它做的事情,因此它有时被称为“可编程编程语言”。(我将在此指出 Lisp 描述了一系列语言,Common Lisp 只是其中的一种方言)。
我认为声明性、命令性、功能性或程序性术语中的哪一个是其中的一个子集并不重要。更重要的是了解您正在使用的工具语言,以及它们与其他工具的不同之处。更重要的是理解范式所代表的不同思维方式,因为它们是你的思维工具。与生活中的大多数其他事情一样,您了解得越多,您就会变得越有效。
看待它的一种方式(并不是说这是正确的方式,因为我无论如何都不是语言设计师或理论家)是,如果语言本质上被转换为其他东西,那么“其他东西”必须是来源。所以字节码必然是Java的超集。.NET IL 是 C# 和 F# 的超集。因此,C#(即 LINQ)中的函数式构造是 IL 的命令式构造的子集。
由于机器语言是命令式的,因此您可以采取这样的立场,即所有语言都是命令式的,因为它们只是对人类有用的抽象,然后被编译器煮沸为程序化的命令式机器代码。
模式映射如
f:: [int] -> int
f [] = 0
f (x:xs) = 1 + f(xs)
是例如在命令式语言中不可用的东西。还构造像柯里化函数:
add2 :: int -> int
add2 = (2 +)
在大多数命令式语言中不可用
是的,函数式编程是命令式编程的一个子集,但是......
是的,因为在函数式编程中没有什么是命令式编程不能做的(尽管有语法差异)。你可以用命令式语言“做”函数式编程。
但是…… 你不能做的是函数式编程的关键特性。通过限制你可以做的事情,
- 你使某些错误成为不可能,
- 您启用功能(例如程序分析、更简单的并发性、更简单的测试等)。
函数式编程的其他好处更加主观。你经常听到这些论点。
- 状态允许副作用。副作用很糟糕。函数式编程没有状态。没有状态就不能产生副作用。
这是一个可疑的好处。首先,只有意外的副作用是不好的。适当的编程实践,例如将状态修改限制为特权代码,可以减轻副作用问题。其次,函数式编程只有没有内部状态。如果程序有 IO(访问文件、网络、硬件),你就有外部状态,因此可能会产生副作用。
- 函数式程序更容易调试。
在某些方面是的,比如知道异常的显式路径。但是检查状态是函数式编程所没有的调试好处。
- 函数式程序更容易理解。
仅当您精通函数式编程而不精通命令式编程时,这才是正确的。一方面,我更精通命令式编程,发现这个论点是错误的。