用于函数式编程的心理模型或真实世界隐喻


16

是否有人对函数式编程有一个很好的思维模型或隐喻,可以引用现实世界中的某些东西?

直观的面向对象编程对我来说很有意义。有些东西具有属性,有时它们也可以对它们的属性(方法)进行填充或执行计算。(例如:汽车,造型,猫)。

我对函数式编程毫无恶意,并且我对辩论两者的优点不感兴趣。与面向对象编程一样,我只需要一个隐喻或思维模型即可使用。

在功能范式中进行编程有哪些好的心理模型或现实世界隐喻?关于由功能处理功能组成的功能的某些说明,使一个功能没有固定的位置来站立和思考。


您指的是“函数式编程”的具体含义,“没有副作用/声明”或“一流的函数/函数组成”?或两者?
快速的

有趣的问题。以我目前对“函数式编程”的编程知识和经验很少,我无法有意义地回答该问题。如果我不敢猜测,我会说两个。
Guido Anselmi 2014年

13
通常将“现实世界”模型作为面向对象编程的动机。我认为这是您最终应该淘汰的一种方法,因为OOP中的对象不应该总是与现实世界中的对象相对应,即使它们确实如此,对应关系通常也不完整。例如,“是”关系并不总是相同的。另一方面,一旦您说您想要基于“现实世界”中某种东西的编程语言的模型或隐喻,我认为您实际上已将自己局限于这种有限形式的OOP。
David K

如果您有使用过类unix的系统(或现代Windows中的powershell)的经验,那么这是一个非常好的心理模型。它们并不完全相同,因为外壳管道从技术上讲是基于流程的编程,而不是功能性的,但是它们具有与程序员相同的“感觉”。
slebetman 2014年

1
此外,在学习函数式语言时,您会发现在函数式编程中,面向对象被视为一种工具,例如正则表达式。如果愿意,可以使用某些东西,但不必这样做。在诸如lisp和tcl之类的某些语言中,OO不是该语言的内置功能,而是您可以使用的库(或者,如果您觉得很勇敢,甚至可以编写自己的OO)。因此,使用大多数功能语言中的OO可以解决自然具有OO解决方案的问题。人们只是不将OO视为一种宗教。
slebetman 2014年

Answers:


32

函数式编程就是将较小的函数粘合在一起以获得结果。体面的心理模型(至少对我而言)是一条装配线。组成的每个功能都是组装过程中的又一个步骤。在此考虑此功能:

smallest  = head . sort

在Haskell中,此函数将返回列表中的最小元素。组装流水线首先对输入进行排序,然后返回第一个元素(假设它的排序最小到最大)。如果我们只想获得最小的偶数,则可以将组装流水线更改为如下所示:

smallestEven = head . sort . filter even

这只是传送带上的又一步。

简而言之,函数只是描述将原始输入(零件)转换为已处理商品(输出)所采取的步骤。


2
在没有全局变量的纯函数式语言中,那么一条组装线不会影响另一条组装线(除非它正在馈送另一条线的输入。)理论上,任何不依赖于彼此的组装线都可以并行执行,但我不是确定是否有编译器执行此操作。
bstamour 2014年

3
@GuidoAnselmi一种思考的方法是,函数式编程中的组装线会生成新的输出,而输入保持不变,而传统OOP中的组装线会转换输入。
Doval 2014年

2
这个隐喻仅在“函数编程”的“一流函数/函数组成”含义中有意义,而在“无副作用/声明性”中则没有意义。同样,面向对象的编程不一定具有副作用,因此您可以使用OOP或FP的这种含义来实现破坏性或构造性的装配线。OOP的主要作用是封装,消息传递和多态性,而不是副作用,它取决于事物建模的方式。例如,您是否需要从头到尾的推荐身份?
快速的

3
@bstamour:准确地说,一个应该编写(f . g) (x)装置f(g(x))f . g手段\x -> f (g (x))
Giorgio 2014年

3
@MarjanVenema在该示例中剩下的事情是因为这样.定义的;这并不是Haskell 通常的工作方式。您也可以|>在Haskell中定义F#的前向管道运算符()并编写smallest x = (sort x) |> head,数据将正确流动。只是以为我会指出这一点。
Doval 2014年

18

有没有人对函数式编程有好的心智模型?

数学。函数式编程的灵感来自数学并以数学为模型。数学函数没有状态,没有副作用等,FP也是如此。如果您从数学函数的角度考虑FP,而不是使用OO风格的“我如何做到这一点”的方法,那么您将处于良好状态。但是,如果您尝试将OO敏感性带给FP,那么您将与时俱进。


1
谢谢。但是,我需要一个来自现实世界的隐喻(例如,不需要来自计算机或数学的隐喻)。
Guido Anselmi 2014年

3
@GuidoAnselmi:一个函数是一个黑匣子。您将某物放入一侧,然后又有新的东西出现。如果您将相同的东西放进去,您总是会得到相同的东西。您可以带很多这样的小盒子,并以不同的顺序将它们组合起来,以建立一个工厂,该工厂可以容纳原金属并生产汽车。在内部,该过程分为许多部分,但是从外部来看,这只是另一个功能。
丹妮丝2014年

16

翻书怎么样

在翻书中,每一页都代表着当时存在的世界。在我们的程序中,世界表示为某种复合数据结构(例如,香蕉在大猩猩的手中,香蕉在丛林的树中)。随后的每个页面都会通过稍微修改前一个表示形式来推进故事。在FP中,持久性数据结构旨在有效地重用以前的结构,以便更改仅提供增量而不提供全新的再现。

可能并不明显的是,我们的翻书中的一页也代表无形资产。例如,如果大猩猩掉落香蕉,我们可能会开始施加重力对其体面和朝向丛林地面的加速度的影响。为了适应这一点,我们将诸如速度和轨迹之类的属性附加到香蕉上。

在我们的程序中,将有一个函数接受一个翻书页面(又称世界状况)作为参数并产生一个新页面。这样,我们的故事就不会实际更改现有对象的状态了。我们只是使用有效的计算方法,用新的页面替换每个页面。


3

关系。

朋友:给定两个人,朋友关系遵循这些一般法律

  1. 对彼此有好感
  2. 认为彼此是他们的朋友(因此在这种关系中,两个成员都必须遵守法律)
  3. 喜欢彼此相处

Monoid:给定多个项目,并且函数接受其中2个项目并返回1,则遵循这些一般定律的monoidal关系

  1. 其中的一项(只有一项,称为身份)会与其他任何项一起传递给函数,以确保函数始终返回一项(0 + 1 = 1,因此当项是数字且功能是加法)
  2. 该函数无法操作或返回不在集合中的项目,它与
  3. 该函数是关联的,可以以某种顺序独立的方式与项目一起使用,这意味着a *(b * c)=(a * b)* c这表示您可以将a乘以b * c或c的结果通过a * b的结果,结果将是相同的,无论您先执行哪个操作。

函数式编程是关于概括的,朋友是一种非常普遍的关系,可以在许多情况下看到,但是在所有各种格式中,它通常都遵循上述定律。

认识到支配事物之间关系的法律,您可以创建适用于具有这种关系类型的事物的任何格式的常规实现。在函数式编程中,您尝试识别事物之间的关系,以便可以对其进行分类和一般处理。

您想从现实世界中隐喻吗?查看事物之间的关系,并尝试确定一般法律(如适用于法律以外的事物可能会发生变化的多种情况)。商店的业务员和购物者之间存在某种关系,它具有一些一般性的法律,已经开发了软件来以POS系统的方式促进人们在这种一般性关系中的目标。同样,当您开始看到这些决定事物之间如何关联的一般规律时,就可以开始依赖那些关系的规律来编写软件,而不是依赖某个关系实例的特定细节。


2

一切都是值,您将函数应用于值(可能是函数)以产生新值,最好不产生任何副作用。


谢谢。不幸的是,听起来更像是一种描述,而不是心理模型或隐喻。我需要一个来自现实世界的隐喻(而不是来自计算机的隐喻)。
Guido Anselmi 2014年

1
正如Caleb指出的那样,函数式编程是对数学进行建模,而不是对现实世界进行建模。它可以通过数学的角度对现实世界进行建模,但是您可能找不到适合您的隐喻,因为FP避开了具有持久身份和可变状态的事物的概念。如果您愿意,我可以指出OOP构造如何映射到FP,但这仍然不是您想要的答案。
Doval 2014年

但是数学是基于现实世界的。1太阳,9行星。2个苹果加2个苹果可以制作4个苹果。
Guido Anselmi 2014年

在函数式编程中,您还可以为太阳,行星和苹果指定一个类型,然后创建一个太阳类型的值,9个行星类型的值,并为苹果类型定义加法。
2014年

3
@GuidoAnselmi您完全落后了,人们用数学分析现实世界,它没有基于现实世界的基础。数学用于分析和定义各种事物之间的关系,无论是真实的还是非真实的。9颗行星是您将具有数学分析功能(计数)的数学构造(自然数集)应用于现实世界构造(行星)。现实世界没有9个行星,它有行星,数学只讨论事物的符号表示,其中符号之间存在联系。
Jimmy Hoffa 2014年

1

关于函数式编程,关键要意识到的是,一切都是一个值-甚至代码本身也是“值”。

简单的功能编程环境的最佳示例是每个人最喜欢的业务工具-电子表格。电子表格中的每个单元格要么是数据,要么是函数的结果。而且,此功能无法关闭并修改另一个单元格。

当一个人移动到功能性语言,而不是笛卡尔网格A1B42,功能有名字。这就是全部。

除此以外,还可以添加其他方面……但这是功能编程的核心。不必担心列表的结构或事物的分组。函数式编程是关于将值传递到函数中并取回值,而不会在内存中的其他地方产生任何混乱。

而已。函数式编程是具有名称而不是网格的电子表格。


0

您可以将函数式编程视为行为。程序是对计算机要执行的行为的描述。功能是行为的基本单位,功能组合是从较小的行为构建较大行为的一种方法。

在OOP中,代码对象旨在成为问题域中对象的状态。它会随着时间而变化,以反映该域对象的变化。在FP中,值表示域对象的状态;它永远不会改变,您只需创建不同的值来表示不同的状态。

我发现功能模型对于计算机的实际表现(表示)更为诚实。毕竟,我不能仅仅new Tesla()凭空想像一下。:)


-5

假设您大致按照以下方式分解句子,它们的功能比面向对象的更多。

The brown cow is in the meadow across the deep river.

因此,我们需要先找到主要短语,然后再找到其余的短语:

The cow (brown)
the meadow (across)
the river (deep)

一气呵成:

sentence: The cow ((the meadow (the river (deep)) (across)) brown)

解析树:

|                     sentence
|                      /         
|                  The cow
|                 /       \
|            the meadow   brown
|            /         \
|      the river      across
|              \
|              deep

简约感染功能性思维;

致敬1890年代的Gottlieb Frege,1930年代的Alan Turing(entschiedungsprobleme),Noam Chomsky(1960年代)。


4
这是一个令人困惑的解释,我从一开始就熟悉FP。
丹妮丝2014年

看起来好像在模仿Lisp的形式却不理解其含义
Izkata 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.