不变性或可变性不是在函数编程中有意义的概念。
计算上下文
这是一个很好的问题,是对另一个最近的问题的有趣的跟进(不是重复):分配,评估和名称绑定之间有什么区别?
与其逐个答复您的陈述,不如说是在这里给您一个结构化的概述。
您可以考虑以下几个问题,包括:
什么是计算模型,什么概念对给定模型有意义
您使用的单词的含义是什么,它如何取决于上下文
函数式编程风格似乎很愚蠢,因为您用命令式的眼神看到了它。但这是一个不同的范例,您的命令性概念和感知是陌生的,与时俱进。编译器没有这种偏见。
但是最后的结论是,有可能以纯粹的功能性方式编写程序,包括用于机器学习的功能,认为功能性编程不具有存储数据的概念。在这一点上,我似乎不同意其他答案。
希望尽管这个答案很长,但仍会有一些人感兴趣。
计算范式
问题是函数编程(又称应用程序编程),这是一种特定的计算模型,其理论上最简单的代表是lambda演算。
如果您仍处于理论水平,则有许多计算模型:图灵机(TM),RAM机等,拉姆达演算,组合逻辑,递归函数理论,半Thue系统等。计算功能越强大事实证明,这些模型可以解决的问题是等效的,这就是Church-Turing论文的要旨
。
一个重要的概念是相互简化模型,这是建立等价关系的基础,该等价关系导致了Church-Turing论文。从程序员的角度来看,将一种模型简化为另一种模型通常称为编译器。如果您将逻辑编程作为计算模型,则它与您在商店中购买的PC提供的模型完全不同,并且编译器会将以逻辑编程语言编写的程序转换为PC代表的计算模型(相当多)。 RAM计算机)。
但是,这并不意味着这两个模型以相同的方式进行操作,也不意味着可以将对一个人有意义的概念转移给另一个人。通常,TM中的计算步骤与Lambda演算中的()还原步骤几乎没有关系,尽管它们可以相互翻译。Lambda表达的最佳评估概念与TM模型中的复杂性问题相去甚远。β
实际上,我们使用的编程语言倾向于混合来自不同理论渊源的概念,并试图做到这一点,以使程序的选定部分可以在适当的情况下受益于某些模型的属性。同样,人员构建系统可以为不同的组件选择不同的语言,以使该语言最适合手头的任务。
因此,您很少会看到以编程语言处于纯状态的编程范例。编程语言仍然根据主要的范式进行分类,但是当涉及其他范式的概念时,语言的属性可能会受到影响,这常常使区分和概念问题变得模糊。
通常,诸如Haskell和ML或CAML之类的语言被认为是功能性的,但是它们可以允许命令式的行为……否则为什么有人会谈到“ 纯功能子集 ”呢?
然后可以声称,可以用我的函数式编程语言来做到这一点,也可以用我的函数式编程语言来做到这一点,但是当函数式编程依赖于可以被认为是额外功能的东西时,它并没有真正回答关于函数式编程的问题。
答案应该与特定范式更精确地相关,而没有额外内容。
什么是变量?
另一个问题是术语的使用。在数学中,变量是一个实体,在某些领域中代表未确定的值。它用于各种目的。在方程式中使用时,它可以代表任何值,以便验证方程式。在逻辑编程中以“ 逻辑变量 ” 的名称使用了这种构想,这可能是因为在开发逻辑编程时,名称变量已经具有另一种含义。
在传统的命令式编程中,变量被理解为某种容器(或存储位置),可以存储值的表示形式,并可能将其当前值替换为另一个值。
在函数式编程中,变量在数学上的作用与作为占位符的目的相同,尚有待提供。在传统的命令式编程中,此角色实际上是由常量扮演的(不要与文字混淆,这些文字是用特定于该值域的符号表示的值,例如123,true,[“ abdcz”,3.14])。
任何种类的变量以及常量都可以由标识符表示。
命令式变量可以更改其值,这是可变性的基础。功能变量不能。
编程语言通常允许从语言中的较小实体构建较大的实体。
命令式语言允许此类构造包含变量,这就是为您提供可变数据的原因。
如何阅读程序
从根本上说,程序是对算法的抽象描述,它是某种语言,无论是实用设计还是范式纯净的语言。
原则上,您可以接受每一个抽象的说法。然后,编译器会将其转换为某种适合计算机执行的格式,但这并不是您首先遇到的问题。
当然,现实会更加苛刻,通常最好对发生的事情有所了解,以避免编译器将不知道如何处理的结构有效执行。但这已经是优化……编译器可能非常适合,通常比程序员更好。
功能编程和可变性
可变性基于命令变量的存在,该命令变量可以包含值,可以通过赋值进行更改。由于这些在函数式编程中不存在,因此一切都可以视为不可变的。
功能编程专门处理值。
关于不变性的前四个陈述大部分是正确的,但是用命令式视图描述了一些非必要性。这有点像在每个人都是盲人的世界中用颜色描述。您正在使用与函数式编程无关的概念。
您只有纯值,而整数数组是纯值。要获得仅在一个元素上不同的另一个数组,您必须使用不同的数组值。更改元素只是在此上下文中不存在的概念。您可能有一个函数,该函数具有一个数组和一些索引作为参数,并且返回的结果是几乎相同的数组,仅在索引指示的位置不同。但是它仍然是一个独立的数组值。这些值的表示方式不是您的问题。也许他们在计算机的命令翻译中“共享”了很多东西……但这是编译器的工作……而您甚至不想知道它正在编译哪种机器体系结构。
您不复制值(没有意义,这是一个外来的概念)。您只需要使用在程序中定义的域中存在的值即可。您要么描述它们(作为文字),要么它们是将函数应用于其他值的结果。您可以给它们命名(从而定义一个常数),以确保在程序的不同位置使用相同的值。注意,函数应用程序不应被视为计算,而应视为对给定参数的应用程序的结果。写作5+2
或写作7
数额相同。与上一段是一致的。
没有命令式变量。无法分配。您只能将名称绑定到值(以形成常量),这不同于命令式语言,您可以将名称绑定到可分配的变量。
这是否会带来复杂性,目前尚不清楚。一方面,您提到的复杂性涉及命令式范例。除非您选择将功能性程序作为命令性程序阅读,否则这并不是功能性编程中的定义,这不是设计者的意图。实际上,功能视图旨在让您不必担心此类问题,而将精力集中在正在计算的内容上。它有点像规范与实现。
编译器必须注意实现,并且要足够聪明,以使其最适合要执行的硬件,无论它是什么。
我并不是说程序员从不为此担心。我并不是说编程语言和编译器技术已经如我们希望的那样成熟。
回答问题
您无需修改现有值(外来概念),但可以根据需要计算出不同的新值,这可能是因为它包含一个额外的元素(它是一个列表)。
该程序可以获取新数据。重点是您用语言表达的方式。例如,您可以考虑该程序使用一个特定的值(可能大小不受限制)工作,该值称为输入流。这个值应该放在这里(无论是否已经完全知道不是您的问题)。然后,您将具有一个函数,该函数返回由流的第一个元素和流的其余部分组成的一对。
您可以使用它以纯粹适用的方式构建通讯组件网络(协程)
当您必须累积数据和修改值时,机器学习只是另一个问题。在函数式编程中,您无需这样做:您只需根据训练数据计算出不同的新值即可。生成的机器也将正常工作。您担心的是计算时间和空间效率。但是,这又是一个不同的问题,理想情况下应由编译器处理。
结束语
从注释或其他答案中可以很清楚地看出,实用的函数式编程语言并非纯粹是功能性的。这反映了我们的技术仍有待改进的事实,尤其是在编译方面。
可以采用纯粹的应用风格进行写作吗?答案已经知道了大约40年,是的。指代语义学的真正目的恰恰是在1970年代出现的,目的是将语言翻译(编译)成纯函数式风格,被认为可以更好地理解数学,因此被认为是定义程序语义的更好基础。
有趣的是,可以通过引入适当的值域(例如数据存储区)将命令式编程结构(包括变量)转换为功能样式。尽管具有功能风格,但它仍然惊人地类似于以命令式风格编写的实际编译器代码。