热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:一派胡言!Swift不是多范式函数式编程语言

“一种世界观。”是的,这就是它的本质所在。


“一种世界观。”是的,这就是它的本质所在。


编程语言范式很像音乐流派。它们是混乱的东西,我们可以争论在哪里画线,什么去哪里,什么是纯粹的以及什么是融合。但就像古典吉他和重金属属于不同的流派一样,即使他们都使用吉他。


我有些朋友说他们对音乐很有鉴赏力。他们标榜自己听“一切”的音乐。从Jimmy Buffet的乡村摇滚到Metallica的重金属音乐,这些乐队演奏的所有音乐他们都喜欢。许多程序员也是如此。他们只知道过程编程和面向对象编程的范式。他们认为BASIC和Java之间的区别就是所有语言之间的区别了。当他们遇到一种新的语言时,他们的第一个问题是“它的语法是什么?”?但是我认为他们的问题应该是“它是如何看待问题的?”


我现在要说很多关于编程范式的事。像音乐流派一样,有很多观点和方法可以对音乐进行分类。我的方法不是唯一的方法。但是有些方法比其他方法更加有用。我想表达的是,因为它们都有map而将Swift和Haskell归为一类编程语言的分类法,并不比因为它们都有vocalists而将Wangga、Opera、和Rock归为一类编程语言的分类法更有用处。


过程式(或命令式)编程主要关注的是将问题分解为一系列的动作。它通常的结构是“执行第一步,然后重复执行第二步,直到某件事是真的,然后执行第三步。”这种范式在流行的编程语言中非常普遍,以至于许多程序员认为这就是编程的全部意义。这当然不是。它只是分解问题的一种方法。当面对一个问题时,过程式编程的问题是:“我需要执行哪些步骤来解决这个问题?”


面向对象编程(OOP)主要关注的是将问题分解为具有属性的自包含对象,以及操作这些属性的方法的集合。它通常的结构是带有实例(对象)的类的层次结构,这些实例继承了属性和方法。当面对一个问题时,面向对象编程的问题是“需要什么样的对象一起工作才能解决此问题?”


这两种思维方式在流行的编程语言中极其普遍,并且可以很好地协同工作。自从第一批机器语言问世以来,过程式编程就一直伴随着我们。即使是早期的自动织布机也是在过程式范式下工作。


自上世纪90年代以来,面向对象编程(OOP)一直是编程的主导。长期以来,它一直是主流的范式,并且一直长时间地主导着CS程序,以至于许多程序员都认为这是必然的。他们认为只有像Fortran这样的“古老语言”才会缺乏对象(而现在,甚至连Fortran都支持对象了)。


但是面向对象编程(OOP)只是思考问题的一种方式。函数式编程是思考问题的另一种方式。函数式编程主要是将问题分解为接受并返回不可变值的函数。它通常的结构是一些将值转换为其他值的函数,以及各种组合函数的方法的集合。它避免了可变状态,并且不要求函数的求值以任何特定的顺序进行。函数式编程将程序视为一个数学问题,而不是一系列操作。当面对一个问题时,函数式编程的问题是“需要以何种方式来转换什么样的值以解决此问题?”


当你第一次开始使用Swift时,你首先要找的是什么?也许是它如何处理类和协议的?也许是如何调用方法,声明和分配变量,定义属性?或者是它们的for和while循环版本?这些都是面向对象编程和过程式编程的工具,你认为它们都是容易获得和易于使用的,这是正确的。你只需要知道语法。


我听到有人将Swift描述为“函数式的”,因此,当我打开我的第一个Swift工作区时,我立即查找Swift中的flatmap的用途。我想知道它是怎么用来将一个列表拆分为头和尾的。我查找了一个foldLeft等效且不可变的集合。Swift似乎对它们都没有进行特殊处理。这并不是说一门语言必须具有这些才能被称之为函数式语言,就像一门语言必须具有for循环才能被称为过程式语言一样。


但是,如果我向你展示了一种新语言,并且说它是面向过程和面向对象的,但是你必须使用if和goto来实现for循环的功能,并且没有类继承,那么你可能会对这种语言的特性选择感到惊讶。一个无法在O(1)时间内简单地将一个列表折分出“第一个”和“不是第一个”元素的“函数式”语言是一种非常奇怪的函数式语言。


Swift特有reduce和map函数,它还具有第一类函数和模式匹配。并且,它还具有在其它函数式语言中也很常见的一些特性。它的语法甚至感觉与Scala非常相似(当我意识到关联值是样式类(case class)时,关于它们的一切就变得有意义了)。但是它并不像其它函数式语言那样思考问题。它们鼓励你在任何可能的地方使用let,但是在一个Swift程序中,你总是会有let和var的混合,并且苹果提供的大多数示例都包含变量。在Scala中工作时,我几乎从不使用可变变量。在Haskell中,可变变量被认为是高级功能,甚至都没有出现在介绍性的书籍中。


这就给我们带来了真正的差异。在Swift中,你基本上是以一个过程式编程/面向对象编程的范式进行工作,并且整个语言都是围绕这个范式构建的。当有需要时,有一些工具可以让你跳到函数编程样式(但没有函数式编程的全部功能)。在Haskell中,你基本上是以函数式编程的范式进行工作。有一些可用的工具(Monad)可以让你在需要过程编程样式(没有过程编程的全部功能)时,跳转到它。


有人可能会说:“Rob,你太直白了。Swift是一种多范式语言,它包含了面向对象编程和函数式编程。”这是一派胡言。Scala才是一种多范式的,面向对象编程/函数式编程。当你在Scala中处理一个问题时,你将其分解为主要在不可变数据结构上工作的对象。这才是面向对象编程/函数式编程的做法。而在Swift中,他们甚至连提供一个不可变列表都不愿意。并不是说他们无法添加它,而是因为这并不是Swift工作的根本。


Swift是一个多范式编程语言,但它不是面向对象/函数式编程的。而是面向对象/泛型编程的。泛型编程主要关注可应用于任意类型的通用算法。它与函数式编程有一些相似之处,当然也有这样的编程语言,它既是函数式的,又是泛型的,但是泛型编程不在乎算法是函数(接受并返回不可变值的东西)还是过程(改变状态的事物)。你可以说Swift不是泛型的,因为它有Array(整形数组)。你可以用非泛型语言实现这种结构。你也可以说Swift是泛型的,因为你可以在整个核心库中找到泛型编程的程序。考虑像advance这样的函数:











/// Return the result of moving start by n positions. If T models/// RandomAccessIndex, executes in O(1). Otherwise, executes in/// O(abs(n)). If T does not model BidirectionalIndex, requires that n/// is non-negative.func advance(start: T, n: T.DistanceType) -> T


这正是你对泛型语言所期望的那种功能。它封装了一种算法,该算法可以在任何实现ForwardIndex的对象上工作。但它不是ForwardIndex实例继承或必须实现的方法。这似乎很微妙,但实际上是一种截然不同的思维方式。


你可以在Swift标准库中看到很多这样的东西,它们正是你希望在泛型语言中找到的东西。很多看起来像“函数”特性的东西实际上只是通用的算法。让我们看看下面的quickSort和reduce函数:











func quickSort (inout elements: C, range: Range, less: (C.GeneratorType.Element, C.GeneratorType.Element) -> Bool)
func reduce(sequence: S, initial: U, combine: (U, S.GeneratorType.Element) -> U) -> U


reduce是一个非常常见的函数工具,它就在quickSort函数旁边,但是没有函数式语言会以这种方式公开它(它改变了集合)。两者都以泛型样式表示。它们只是算法。一个可以改变集合,另一个不可以。重要的是算法可以在多种数据上重复使用,这就是泛型编程。我们得到了一些函数特性,但这其实只是它的一个副作用,而不是它的范式。


这些都不是对Swift的批评。没关系,它不是函数式语言。我本来想,要是所有Cocoa开发都是函数式编程就好了,但这只是因为我喜欢它。我不知道这是否会进一步实现真正出色的ios和Mac应用程序的目标(至少在短期内)。不是说FRP(函数响应式编程)不是个好主意。对此我没有什么强烈的意见。只是与Swift.2相比,ObjC程序员的学习曲线很高2,而我们需要将Swift与(非函数式的)ObjC集成很长一段时间。


我希望随着时间的推移,Swift将会包含更多的函数特性。if和switch应该返回值。应该允许在模式匹配中将一个列表拆分成头和尾(这点应该很轻松就能实现)。函数应该接受具有强制尾调用优化的“尾递归”属性。可变方法应该很少用,不可变的数据类型应该更多。


这些东西都不会使得Swift自己成为函数式语言。但是足够多的这些东西可以让我们用更多的函数功能模式来编写代码,也许有朝一日,Swift和Cocoa可以真正成为函数式编程语言。如果这是最终的结果,那么Swift可能会成为一门出人意料的重要语言,它可以改进编程规程,因为程序员必须学习函数式编程才能在一个非常流行的平台上开发。学习函数式编程可以让你成为一个更好的程序员,即使你使用其他范式工作。


或者这些都不会发生,Swift可能只是一种编写非常出色的iOS和Mac应用程序的语言,但这也没关系。





  1. 我相信所有这些东西在Swift中实现都会非常简单。但是他们并没有跳出文档的框框,甚至在任何Swift视频中都没有讨论过这些内容。这是一种对什么是重要的和什么是可能的一种衡量。它们会告诉你所用的范式。



  2. 我在Scala中进行反应式UI编程的经验好坏参半。即使有函数式编程的背景,我发现我的学习曲线仍然很高,并且程序很难调试。但这可能只是需要更多的经验。这似乎是个好主意,我只是不知道它是否真的是个好主意。



  3. 我以前骑摩托车。当你骑摩托车的时候,你必须比开车的时候更加清醒。否则,你会受伤的。但是我注意到的是,骑摩托车使我成为了更好的汽车驾驶员。函数式编程就是这样。骑摩托车不一定是到达目的地的最佳方式,但是如果每个人都学会了骑摩托车,我们会拥有更好的驾驶员。如果大学先教Haskell,然后再教Java,我们就会有更好的程序员。







原文链接:
https://robnapier.net/swift-is-not-functional






本文为CSDN翻译文章,转载请注明出处。






【END】


一派胡言!Swift 不是多范式函数式编程语言

更多精彩推荐




今日福利:评论区留言入选,可获得价值299元的「2020 AI开发者万人大会」在线
直播门票一张
。  快来动动手指,写下你想说的话吧。


点击阅读原文,精彩继续!














你点的每个“在看”,我都认真当成了喜欢







推荐阅读
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • 花瓣|目标值_Compose 动画边学边做夏日彩虹
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Compose动画边学边做-夏日彩虹相关的知识,希望对你有一定的参考价值。引言Comp ... [详细]
  • 颜色迁移(reinhard VS welsh)
    不要谈什么天分,运气,你需要的是一个截稿日,以及一个不交稿就能打爆你狗头的人,然后你就会被自己的才华吓到。------ ... [详细]
  • 1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 2.对于随机访问get和set,ArrayList优于LinkedList,因为Ar ... [详细]
  • 给定一个二维平面上的一些点,通过计算曼哈顿距离,求连接所有点的最小总费用。只有任意两点之间有且仅有一条简单路径时,才认为所有点都已连接。给出了几个示例并给出了对应的输出。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • 摘要: 在测试数据中,生成中文姓名是一个常见的需求。本文介绍了使用C#编写的随机生成中文姓名的方法,并分享了相关代码。作者欢迎读者提出意见和建议。 ... [详细]
  • 本文介绍了安全性要求高的真正密码随机数生成器的概念和原理。首先解释了统计学意义上的伪随机数和真随机数的区别,以及伪随机数在密码学安全中的应用。然后讨论了真随机数的定义和产生方法,并指出了实际情况下真随机数的不可预测性和复杂性。最后介绍了随机数生成器的概念和方法。 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
author-avatar
陈旺财九_999
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有