为什么说面向对象编程和函数式编程都有问题(代码片段)

AlanTu AlanTu     2022-10-22     371

关键词:

我不理解为什么人们会对面向对象编程和函数式编程做无休无止的争论。就好象这类问题已经超越了人类智力极限,所以你可以几个世纪的这样讨论下去。经过这些年对编程语言的研究,我已经清楚的看到了问题的答案,所以,我经常的发现,人们对这些问题做的都是一些抓不住要领、无意义的争论。

简言之,不论是面向对象编程还是函数式编程,如果你走了极端,那都是错误的。面向对象编程的极端是一切都是对象(纯面向对象)。函数式编程的极端是纯函数式编程语言

面向对象编程的问题

面向对象的问题在于它对“对象”的定义,它试图将所有事情就纳入到这个概念里。这种做法极端化后,你就得出来一个一切皆为对象思想。但这种思想是错误的,因为

有些东西不是对象。函数就不是对象。

也许你会反驳,在Python和Scala语言里,函数也是对象。在Python中,所有的含有一个叫做__call__的方法的对象其实都是函数。类似的,在Scala语言里,函数是拥有一个叫做apply方法的对象。但是,经过认真的思考后,你会发现,它混淆了源祖和衍生物的概念。函数是源祖,包含函数的对象实际是衍生物。__call__apply它们自身首先就是要定义的所谓“函数对象”。Python和Scala实际上是绑架了函数,把它们监禁在“对象”里,然后打上“__call__” 和 “apply” 标签,把它们称作“方法”。当然,如果你把一个函数封装到对象里,你可以像使用一个函数那样使用对象,但这并不意味着你可以说”函数也是对象“

大多数的面向对象语言里都缺乏正确的实现一等(first-class)函数的机制。Java语言是一个极致,它完全不允许将函数当作数据来传递。你可以将全部的函数都封装进对象,然后称它们为“方法”,但就像我说的,这是绑架。缺乏一等函数是为什么Java里需要这么多“设计模式”的主要原因。一旦有了一等函数,你将不再需要大部分的这些设计模式。

函数式编程的问题

相似的,函数式编程走向极端、成为一种纯函数式编程语言后,也是有问题的。为了讨论这个问题,我们最好先理解一下什么是纯函数式编程语言。出于这个目的,你可能需要阅读一下Amr Sabry先生(他是我的博士导师)的What is a Purely Functional Language。概述一下就是,纯函数式编程语言是错误的,因为

有些东西不是纯的。副作用是真实存在的。

所谓纯函数,基本上就是忽略了物质基础(硅片、晶体等)表现的特性。纯函数式的编程语言试图通过函数——在函数中传入传出整个宇宙——来重新实现整个宇宙。但物理的模拟的是有区别的。“副作用”是物理的。它们真实的存在于自然界中,对计算机的效用的实现起着不可或缺的作用。利用纯函数来模拟它们是注定低效的、复杂的、甚至是丑陋的。你是否发现,在C语言里实现一个环形数据结构或随机数发生器是多么的简单?但使用Haskell语言就不是这样了。

还有,纯函数编程语言会带来巨大的认知成本。如果你深入观察它们,你会看到monads使程序变得复杂,难于编写,而且monad的变体都是拙劣的修改。monads跟Java的“设计模式”具有相同的精神本质。使用monad来表现副作用就像是visitor模式来写解释器。你是否发现,在很多其它语言里很简单的事情,放到Haskell语言就变成了一个课题来研究如何实现?你是否经常会看到一些有着诸如“用Monadic的方式解决一个已经解决的问题”这样标题的论文?有趣的是,Amr Sabry先生一起合著了这样一篇论文。他试图用Haskell语言重新实现Dan Friedman的miniKanren,但他不知道如何构造这些monads。他向Oleg Kiselyov——公认的世界上对Haskell类型系统知识最渊博的人——求教。而且你可能不知道,Amr Sabry先生应该是世界上对纯函数编程语言知识最渊博的人了。他们在 Oleg 的帮助下解决了疑难后一起合著了这篇论文。讽刺的是,Dan Friedman——这个程序的原作者——在使用Scheme语言开发时却没有遇到任何问题。我在Dan的代码基础上重新实现了miniKanren,增加了一个复杂的负操作。为了实现这个,我需要使用约束式逻辑编程和其它一些高级的技巧。鉴于用Haskell语言重写基本的miniKanren将两位世界级程序员都难倒了的事实,我不敢想象如果用Haskell的monads如何能实现这些。

有些人认为monads的价值在于,它们“圈定”了副作用的范围。但如果monads不能真正的使程序变得易于分析或更安全,这种“圈定”有什么用呢?事实上就是没用处。本身就跟副作用一样难于分析理解。没有一种东西可以说monads能使其简单而静态分析办不到的。所有的静态分析研究者都知道这点。静态分析利用了monads的本质,但却去除了程序员编写monads代码的负担——而不是增加负担。当然,过度的副作用会使程序很难分析,但你也可以使用C语言写出纯函数,例如:

int f(int x) 
    int y = 0;
    int z = 0;
    y = 2 * x;
    z = y + 1;
    return z / 3;
  

你用汇编语言也能做到这些。纯函数并不专属于纯函数式编程语言。你可以用任何语言写出纯函数,但重要的是,你必须也应该允许副作用的存在。

回首历史,你会发现,数学上的理想主义是纯函数编程语言的背后推动力。数学函数简单漂亮,但不幸的是,它们只是在你构建原始纯粹的模型时才好用。否者它们会变得很丑陋。不要被“范畴论”等标语吓倒。我对范畴论了解很多。即使是范畴理论学家自己也称其为“抽象无意义”,因为它们基本上就是用一种怪诞的方式告诉你一些你已经知道的事情!如果你读过Gottlob Frege的文章Function and concept,你会吃惊的发现,在他的这篇论文前的大多数数学家都错误的理解了函数,而这仅仅是刚刚100多年前的事。事实上,数学语言上的很多事情都是有问题的。特别是微积分方面。编程语言的设计者们没有理由要盲目的学习数学界。

不要盲目的爱上你的模型

无论任何事情,当走向极端时都是有害的。极端化时,面向对象编程和函数式编程都试图把整个世界装入它们的特有模型中,但这个世界是在完全不依赖我们的大脑思考的情况下运转的。如果以为你有一个锤子,就把所有东西都当成钉子,这明显是不对的。只有通过认清我们的真实世界,才能摆脱信仰对我们的束缚。

不要让世界适应你的模型。让你的模型适应世界。

面向对象编程(代码片段)

...式即编程的方法论,标识一种编程风格.三大编程范式:1.面向过程编程:面向过程是一种以事件为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步骤中再按顺序调用函... 查看详情

面向对象(代码片段)

一.函数式编程和面向对象的对比  面向过程:根据业务逻辑从上到下写垒代码  函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可  面向对象:对函数进行分类和封装,让开发“更快更好更强..... 查看详情

scala学习(函数式编程面向对象编程)(代码片段)

...础函数编程函数定义函数参数函数至简原则高阶函数编程面向对象编程基础面向对象编程高阶面向对象编程函数式编程基础函数编程函数定义packagelearn03objectdemo01defmain(args:Array[String]):Unit=//无参、无返回值deffun1():Unit=println(&... 查看详情

scala学习(函数式编程面向对象编程)(代码片段)

...础函数编程函数定义函数参数函数至简原则高阶函数编程面向对象编程基础面向对象编程高阶面向对象编程函数式编程基础函数编程函数定义packagelearn03objectdemo01defmain(args:Array[String]):Unit=//无参、无返回值deffun1():Unit=println(&... 查看详情

编程的宗派(代码片段)

...争论这类问题,到底是“函数式编程”(FP)好,还是“面向对象编程”(OOP)好。既然出了两个帮派,就有人积极地做它们的帮众,互相唾骂和鄙视。然后呢又出了一个“好好先生帮”,这个帮的人喜欢说,管它什么范式呢,... 查看详情

面向对象_实例化对象和类(代码片段)

首先我们可以看一下面向过程式编程#面向过程编程测量对象的元素个个数。s1=‘fjdsklafsjda‘count=0foriins1:count+=1l1=[1,2,3,4]count=0foriinl1:count+=1面向过程编程再来看一下函数式编程deffunc(s):count=0foriins:count+=1returncountfunc(‘fdsafdsa‘)func([... 查看详情

面向对象(代码片段)

面向对象个面向过程编程的理解:面向对象编程和函数式编程(面向过程编程)都是程序设计的方法,不过稍有区别。面向过程编程:1.导入各种外部库2.设计各种全局变量3.写一个函数完成某个功能4.写一个函数完成某个功能5.... 查看详情

函数式编程(代码片段)

...tionalProgramming(函数式编程)在概念上和ObjectOrientedProgramming(面向对象编程),ProceduralProgramming(过程化编程)类似,是一种编程范式。与OOP以对象为中心的理念不同,FP将所有计算机的操作视为函数运算,函数是操作的基本单位。函数拥... 查看详情

函数式编程与面向对象编程[关闭]

】函数式编程与面向对象编程[关闭]【英文标题】:FunctionalprogrammingvsObjectOrientedprogramming[closed]【发布时间】:2011-01-0522:39:56【问题描述】:到目前为止,我主要接触OO编程,并期待学习一门函数式语言。我的问题是:什么时候选... 查看详情

面向对象编程

一、概述  在学习面向对象之前,我们用函数来封装我们的功能,当我们要使用时,就调用函数来实现我们的需求。现在我们学习了面向对象的知识,知道了类和对象,其实函数式编程和面向对象编程都可以减少重复代码,不... 查看详情

面向对象编程(代码片段)

...式即编程的方法论,标识一种编程风格.三大编程范式:1.面向过程编程:面向过程是一种以事件为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步骤中再按顺序调用函... 查看详情

混合面向对象和函数式编程

】混合面向对象和函数式编程【英文标题】:Mixingobject-orientedandfunctionalprogramming【发布时间】:2010-11-0404:13:18【问题描述】:有哪些语言可以同时促进面向对象和函数式编程?我知道任何支持一流函数的语言都可以被认为是函数... 查看详情

函数和函数式编程(代码片段)

...nc2()1112print("fromfunc1returnis%s"%x)13print("fromfunc2returnis%s"%y)2、为什么要用函数?可扩展,保持一致性,代码重用。1importtime2deflogger():3time_format="%Y-%m-%d%X"4time_current=time.strftime(time_format)5withopen(‘a.txt‘,‘a+‘)asf:6f.write("%sendaction"%time_curr... 查看详情

用函数式编程,从0开发3d引擎和编辑器:函数式编程准备(代码片段)

...为正式开发做好了准备。函数式编程的优点1.粒度小相比面向对象编程以类为单位,函数式编程以函数为单位,粒度更小。正所谓:我只想要一个香蕉,而面向对象却给了我整个森林2.性能好大部分人认为函数式编程差,主要基... 查看详情

05-2函数基础(代码片段)

...,我们写的代码都是函数式编程。之后,我们会一直使用面向对象编程。1函数式编程和面向对象编程的区别函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可面向对象:对函数进行分类和封装,让开... 查看详情

面向对象编程(代码片段)

面向对象编程文章目录面向对象编程两种编程方式类和对象的定义面向对象编程三步骤一、定义类二、造对象三、发消息案例静态方法、类方法面向对象解决实际问题魔术方法面向对象四大支柱继承多态对象之间的关系最终总结... 查看详情

面向对象(代码片段)

面向对象面向对象初识1.1回顾面向过程编程vs函数式编程#面向过程编程测量对象的元素个个数。s1=‘fjdsklafsjda‘count=0foriins1:count+=1l1=[1,2,3,4]count=0foriinl1:count+=1函数式编程deffunc(s):count=0foriins:count+=1returncountfunc(‘fdsafdsa‘)func([1,2,3,4... 查看详情

函数式编程--为什么要学习函数式编程?(代码片段)

函数式编程(FunctionalProgramming,FP)什么是函数式编程?通过纯函数来实现一些细粒度的函数,然后把这些细粒度的函数组合成功能更强大的函数,这一过程就是函数式编程,经典函数式编程库:lodash函数式编程是编程范式之一,... 查看详情