【问题标题】:Is functional programming a subset of imperative programming?函数式编程是命令式编程的子集吗?
【发布时间】:2010-12-19 11:51:43
【问题描述】:

函数式编程的主要特点之一是使用无副作用的函数。然而,这也可以用命令式语言来完成。递归和 lambda 函数(例如 C++0x)也是如此。因此,我想知道命令式编程语言是否是函数式编程语言的超集。

【问题讨论】:

  • 有趣的问题...在命令式编程中,我相信你有更多“上吊”的方法:-)
  • 就“无副作用的功能”而言,我同意您的想法。可以在两种范式中编写和使用“无副作用函数”库,而有状态命令式过程不能用于函数式编程。

标签: programming-languages functional-programming imperative-programming


【解决方案1】:

可以用一种本机不支持该编程范式的语言来实现某种编程范式。例如,可以在 C 中编写面向对象的代码,但它不是为此目的而设计的。

函数式编程本身就是一种发展良好的编程范式,最好通过 Haskell、LISP 等语言学习。在你学会了它们之后,即使你不经常使用这些语言,你也可以开始使用这些语言您经常使用的日常语言中的原则。

有些人可能喜欢谷歌Object oriented programming in C

【讨论】:

  • 你所说的关于 C 的内容没有任何意义,除非你可以拥有一个“对象”。没有多态和继承的OOP是什么意思?
  • 如果你愿意,你可以在 c 中实现你自己的 vtables
  • 当然可以用C编写面向对象的代码;早在 80 年代后期,我们就在一个项目中做到了这一点,当时我们在没有 OO 语言的 OS/2 上工作。它确实需要大量(并且有点疯狂)的宏来实现多态性和继承,但它确实有效。
  • 我的理解是标准的C编译器可以编译Objective-C代码。 Objective-C 编译可以在本地完成(即在编译器中内置支持),也可以使用一组将 OO 结构转换为标准 C 的宏 - 在这种情况下,Objective-C 是一种面向对象的语言,实现为一个层在非 OO 语言上。鉴于此(我相信还有其他例子)IMO 他所说的关于 C 的说法确实有道理
  • 你可以用 C 为 OO 语言编写解释器或编译器。通常在大学里作为练习来完成。
【解决方案2】:

我真的不能说它们是否是彼此的子集。不过,我可以说的是(除了非常深奥的语言)它们都是Turing-complete,这意味着最终它们都同样强大,但不一定同样具有表达能力。

【讨论】:

  • 如此真实......我希望我得到的不仅仅是 +1。
  • Stephen Wolfram 会说“能够进行通用计算”之类的。
【解决方案3】:

范式是一种做事方式,有两种主要的编程范式:命令式和声明式。某些语言允许混合两种范式这一事实并不意味着其中一种包含在另一种中,而是语言多范式

为了更清楚一点,让我继续你的类比:如果 Lisp 和 OCaml(例如)被认为是函数式语言,并且它们都允许命令式风格......那么命令式应该被认为是函数式的子集?

【讨论】:

  • Lisp(特别是Common Lisp)通常被称为多范式语言。您可以相对轻松地编写命令式代码和函数式代码。
  • Lisp 与 C++ 一样被称为多范式。纯粹主义者会说它们是多范式(他们是对的),但在通常的用法中,它们通常分别称为函数式和命令式/面向对象。无论如何,我的观点是,如果你可以同时做这两种范式,那么语言多范式,所以从一开始就错误地陈述了op的问题。
【解决方案4】:

一般来说,没有;函数式编程是声明式编程(包括逻辑编程语言,如 Prolog)的子集。许多命令式语言从函数式编程语言中借用元素,但仅仅拥有 lambda 或引用透明函数并不能使命令式语言成为函数式语言;函数式编程不仅仅是这些元素。

【讨论】:

  • 真的吗?我用 Prolog 和一些涉及 SQL 的东西写过程序,而且我写过纯粹的函数式程序。这两个在我看来并不相似。
  • 它们的相似之处在于您告诉计算机做什么(即表达计算的逻辑)而不是如何去做吧;这就是声明式编程的定义。
  • 纯函数式语言是,但作为非纯函数式语言再次重叠而不是一个适当的子集。
  • @mipadi 您从哪里提出“函数式编程是声明式编程的子集”?
  • @rickmed:来自声明式编程的定义。
【解决方案5】:

大多数命令式语言没有函数作为一阶类型,而大多数函数式语言都没有。 (和 C++ 一样,通过 boost::function。)

通过一阶类型,这意味着一个值/变量可以是任何类型,一个 int、一个 bool、一个来自 int->bool 的函数。它通常还包括闭包或绑定值,其中您具有相同的功能,但已经填充了一些参数。

这两个是函数式编程的主要内容,恕我直言。

【讨论】:

    【解决方案6】:

    模式映射如

    f:: [int] -> int
    f [] = 0
    f (x:xs) = 1 + f(xs)
    

    是例如命令式语言中不可用的东西。 也构造像柯里化函数:

    add2 :: int -> int
    add2 = (2 +)
    

    在大多数命令式语言中不可用

    【讨论】:

    【解决方案7】:

    我认为区分范式语言可能会有所帮助。

    对我来说,范式代表“思维方式”(概念和抽象,例如函数、对象、递归),而语言提供“做事方式”(语法、变量、评估)。

    所有真正的编程语言都是等效的,因为它们是图灵完备的并且理论上能够计算任何图灵可计算的函数以及模拟或由通用图灵机模拟。

    有趣的是用某些语言或范式完成某些任务有多么困难,该工具对任务有多合适。甚至康威的生命游戏也是图灵完备的,但这并不让我想用它来编程。

    许多语言支持多种范式。 C++ 被设计为 C 的面向对象的扩展,但可以在其中编写纯过程代码。

    随着时间的推移,某些语言会从其他语言或范式中借用/获取特性(只需看看 Java 的演变)。

    一些语言,如 Common Lisp,是令人印象深刻的多范式语言。可以在 Lisp 中编写函数式、面向对象或过程式的代码。可以说,面向方面已经是通用 lisp 对象系统的一部分,因此“没什么特别的”。在 Lisp 中,很容易扩展语言本身来做任何你需要它做的事情,因此它有时被称为“可编程编程语言”。 (这里我要指出 Lisp 描述了一个语言家族,Common Lisp 只是其中的一种方言)。

    我认为声明性、命令性、功能性或程序性术语中的哪一个是其中的子集并不重要。更重要的是了解您正在使用的工具语言,以及它们与其他工具的不同之处。更重要的是理解范式所代表的不同思维方式,因为它们是你的思维工具。与生活中的大多数其他事情一样,您了解得越多,您就会变得越有效。

    【讨论】:

    • "不管哪个术语是哪个子集":我问这个的部分原因是因为我喜欢函数式编程的一些概念,但我不喜欢就像它的局限性一样,比如处理 I/O 的方式出了名的困难和递归的广泛使用。
    • 递归是从什么时候开始的?循环和递归是同一枚硬币的两个方面,但一个往往比另一个更合适。函数式编程是一种范式,特定的语言(它的语法和它的库)决定了它对 I/O 或循环之类的“难度”。你使用“臭名昭著”这个词表明你没有好好审视自己。请这样做 - 我发现在 Java 2 中 I/O 非常“难以”掌握,但我只使用 Javadocs 来解决这个问题。选择一种对您来说似乎“友好”的语言并开始阅读它。
    【解决方案8】:

    看待它的一种方式(并不是说这是正确的方式,因为我无论如何都不是语言设计师或理论家)是如果该语言本质上被转换为其他东西那个“别的东西”必须是源的超集。所以字节码必然是Java的超集。 .NET IL 是 C# 和 F# 的超集。因此,C# 中的函数式构造(即 LINQ)是 IL 的命令式构造的子集。

    由于机器语言是命令式的,因此您可以采取这样的立场,即所有语言都是命令式的,因为它们只是对人类有用的抽象,然后被编译器煮沸为程序化的命令式机器代码。

    【讨论】:

    • +1 好话!我想投票,但它不起作用(“投票太旧而无法更改”)。对不起:(
    【解决方案9】:

    是的,函数式编程是命令式编程的一个子集但是...

    是的,因为在函数式编程中没有什么是您在命令式编程中不能做到的(尽管存在语法差异)。你可以用命令式语言“做”函数式编程。

    但是……不能做的事情是函数式编程的关键特性。 通过限制你可以做的事情,

    1. 你不可能犯某些错误,
    2. 您启用功能(例如程序分析、更简单的并发性、更简单的测试等)。

    函数式编程的其他好处更加主观。 你经常听到这些论点。

    1. 状态允许副作用。副作用很糟糕。函数式编程没有状态。没有状态就不会产生副作用。

    这是一个可疑的好处。 首先,只有意外副作用是不好的。适当的编程实践,例如将状态修改限制为特权代码,可以减轻副作用问题。 其次,函数式编程只有没有内部状态。如果程序有 IO(访问文件、网络、硬件),则您有外部状态,因此可能会产生副作用。

    1. 功能程序更容易调试。

    在某些方面是的,比如知道异常的显式路径。 但是检查状态是函数式编程所没有的调试优势。

    1. 函数式程序更容易理解。

    只有当您流利函数式编程并且不流利命令式编程时,这才是正确的。 一方面,我更精通命令式编程,发现这个论点是false

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-16
      • 1970-01-01
      • 1970-01-01
      • 2014-03-20
      • 1970-01-01
      相关资源
      最近更新 更多