【问题标题】:Difference between OOP and Functional Programming (scheme) [closed]OOP 和函数式编程(方案)之间的区别 [关闭]
【发布时间】:2011-10-06 21:56:23
【问题描述】:

我正在观看斯坦福大学的视频课程/讲座。课程是《计算机程序的结构与解释》

在第一堂 OOP 讲座中,讲师 (Brian Harvey) 将 OOP 方法描述为对同一问题给出不同答案的方法,而函数式编程中的函数为特定输入提供特定输出。

以下代码是 OOP 中方法的示例,每次调用时都会给出不同的答案:-

(define-class (counter)
  instance-vars (count 0))
  (method (next)
    (set! count (+ count 1))
    count) )

现在虽然课程是用scheme来说明的,但是我没有太注意语言本身,所以我无法解释代码;但是一个类似的函数“next”不能和这个“next”函数做同样的事情吗? 在 C 中,我会声明一个全局变量,每次调用 next 时将其加一。我知道 C 是程序化的,但我猜想在 Scheme 中也可以做类似的事情。

【问题讨论】:

  • @Matt 虽然斯坦福在某个时候正在/正在使用 SICP (mitpress.mit.edu/sicp/adopt-list.html),但我认为 OP 指的是 B Harvey 的伯克利讲座:youtube.com/watch?v=zmYqShvVDh4
  • SICP?那是麻省理工学院,不是斯坦福大学。
  • set! 可以说是非功能性的,因为它是一个可变赋值;-) 但是,没有理由 new "OO[P]" 对象不能' t 被创建。因此......它有点正交,除了模型如何舒适地工作。使用 C,您可以使用 structures 获得“OO[P]”。虽然没有内置的多态性或其他“OO[P]”特性,但也不需要全局变量。
  • 你能澄清你的问题吗?我很难理解它。此外,如果您想享受并理解这些讲座,您必须了解方案的工作原理并在其中编写几个简单的程序(例如:尝试重现讲座中看到的书面程序)。
  • 无论如何,你的问题是什么? “类似的函数'next'不能做与这个'next'函数相同的事情吗?”

标签: oop functional-programming scheme


【解决方案1】:

优秀的Haskell wiki上有一个页面,其中differences in Functional Programming and OOP是对比的。除了帮助使用 Haskell 语言之外,Haskell wiki 是一个很好的资源关于一般函数式编程的一切

函数式编程与 OOP 的区别

纯函数式编程和面向对象编程的重要区别在于:

面向对象:

数据:

  • OOP 询问 我可以用这些数据做什么?
  • 生产者:类
  • 消费者:类方法

状态:

  • OOP 中的方法和对象具有一些内部状态(方法变量和对象属性),它们可能具有影响计算机外围设备状态、全局范围或对象或方法状态的副作用。变量赋值是事物具有状态的一个好兆头。

功能:

数据:

  • 函数式编程问数据是如何构造的?
  • 生产者:类型构造器
  • 消费者:功能

状态:

  • 如果纯函数式编程曾经为变量赋值,则必须将变量视为不可变变量并将其处理。 纯函数式编程中不能有状态。
  • 具有副作用的代码通常与主要的纯功能代码体分开
  • 状态可以作为参数传递给函数,这称为continuation

OOP 生成器的功能替代品

使用纯函数式编程执行类似于 OOP 样式生成器(具有内部状态)的方法是从不同的角度解决问题,根据用例使用以下解决方案之一:

1.按顺序处理部分或全部值:

序列类型可以是列表、数组、序列或向量。

  • Lisp 有car,Haskell 有first,它们从列表中获取第一项。

  • Haskell 也有 take,它采用前 n 项,支持惰性求值,因此支持无限或循环序列——就像 OOP 生成器一样。

  • 两者都有first,以及不同的mapreducefold函数,用于处理带有函数的序列。

  • 矩阵通常也有一些方法可以为每个项目提供mapapply 一个函数。

2。需要来自函数的一些值:

索引可能来自离散或连续尺度(整数或浮点数)。

  • 创建一个纯函数来生成索引(事件)并将其提供给另一个纯函数(行为)。这称为Functional reactive programming。这是Dataflow programming 的一种形式以及面向单元的编程。 Actor model 在操作上也有些相似,并且是处理并发的线程的一个非常有趣的替代方案!

3.使用闭包从外部限制和封装状态

  • 这是最接近使用生成器的 OOP 方式的替代方法(我认为它实际上起源于模仿闭包),也最远离纯函数式编程,因为闭包具有状态。

【讨论】:

  • 问:那么,如何才能在屏幕上打印或写入磁盘而不会产生副作用?答:这是不可能的。在 Haskell 语言中,绝对需要有副作用的部分,被限制在少数函数中,通常使用Monads 来处理副作用,程序的其余部分是纯函数式编程没有副作用。
  • 从 OOP 语言开始使用 monad 可能听起来令人困惑,但一旦你已经掌握了编写程序的函数式方法,它们就不是真的了。当来自 OOP 时,不要尝试先使用它们!首先学习使用纯函数,编写大部分程序没有副作用。
  • Monad 也是纯粹的,它们只是描述做某事的意图。您可以组合其他意图来创建更大的程序。 haskell 程序只是返回执行操作的意图(这就是为什么 main 具有类型 IO ()) - 当它被编译并运行时,该意图正在被执行并且副作用实现。
【解决方案2】:

嗯。尽管对讲师给予了应有的尊重,但这些对“OOP”和“函数式编程”的定义都有些可疑。这两个术语在工业和学术环境中都一致使用,嗯,不一致,更不用说非正式使用了。如果你再深入一点,真正发生的事情是有几个正交的概念——在如何处理程序时选择不同的轴——它们被混为一谈,其中一组选择被任意称为“ OOP”尽管没有其他任何东西将它们联系在一起。

这里涉及的两个最大区别可能是:

  • 身份与价值:您是否通过隐式身份(基于内存位置等)对事物进行建模并允许它们任意更改?或者你是根据它们的价值来建模事物,没有固有的身份概念?如果你说x = 4 是否意味着x 是永恒柏拉图理想的数字4 的别名,或者x 是当前为四的事物的名称,但以后可能是其他事物(虽然仍然是x)?

  • 数据与行为:您是否使用可以检查、操作和转换表示的简单数据结构?或者您是否使用抽象的行为来做事,仅根据您可以用它做的事情来表示数据,并让这些行为抽象相互操作?

大多数标准命令式语言都倾向于使用标识和数据——指向 C structs 的指针尽可能纯粹地使用这种方法。 OOP 语言的定义主要是通过选择行为而不是数据来定义,通常也倾向于标识但不一致(参见“不可变”对象的流行)。

函数式编程通常更倾向于价值观而不是身份,同时在不同程度上混合数据和行为。

这里还有很多事情要做,但我认为这是你想知道的关键部分。


如果有人好奇,我之前已经详细阐述了其中的一些内容:Analyzing some essential concepts of many OOP languagesmore on the identity/value issue and also formal vs. informal approachesa look at the data/behavior distinction in functional programming,可能还有一些我想不出来的。警告,我有点啰嗦,这些不适合胆小的人。 :P

【讨论】:

    【解决方案3】:

    函数式编程中的“Functional”传统上是指数学函数的含义。也就是说,数学函数的输出仅基于传递给它的输入。现在这种编程更常被称为纯函数式编程。

    在纯函数式编程中不允许重新分配状态,因此无法编写像 C 示例这样的函数。您只能将值绑定到变量一次。 Haskell 就是一个不可能实现的语言示例。

    大多数函数式编程语言(包括方案)都是不纯的,并且允许您这样做。话说,讲师讲的是,写这样的函数在传统意义上的函数式编程中是不可能的。

    【讨论】:

      【解决方案4】:

      嗯,是的,你可以在 C 中做到这一点。
      但它不一样 - 在 C++ 中,您可以让每个对象都有自己的count

      【讨论】:

        猜你喜欢
        • 2020-03-27
        • 2014-12-15
        • 1970-01-01
        • 2010-09-06
        • 2015-01-15
        • 1970-01-01
        • 2020-06-04
        • 2019-03-20
        相关资源
        最近更新 更多