我开始玩Kotlin,但是我在编程方式上感觉到了自己的局限性。我的问题是我仍然认为Java因此风格仍然势在必行,我的问题是所有函数式编程狂热者,我认为这对所有在开始阶段并且需要“制动”他们的大脑的人来说非常有用。再次开始建设;离开舒适区并开始思考伪而不是“你的第一语言”。我相信经验丰富的多语言开发人员可以将这些概念扼杀到关于什么使您的程序以完全功能的方式编写以及违反范例的简单建议。我不知道所有的怪癖,但请不要犹豫,包括我可能不知道的普遍接受的术语(我总是可以查找)。在这一点上,我需要这套规则让自己一开始受苦而不是打破它们,但后来我知道我会感受到它,分析指导方针并理解它们如何变得更好/更好当然是我自己的功课。
这些指南的例子如下:
我希望答案能让我长期参考,让自己处于极端条件下,每当我感到不舒服时,我就会停止逃避OOP。而现在,当我看到Kotlin时,我理解我应该如何思考问题,而不是关于一种语言或另一种语言强加的结构。意图总是可以转换为您选择的语言,并以适用于该语言的设计模式作为后盾,但要找到我需要首先从舒适区域入狱的中间地带。
答案 0 :(得分:2)
避免像瘟疫这样的可变状态。
使用函数式编程(可能是主要的编程)的一个要点是避免在使用可变状态时需要处理的所有小缺陷,错误和问题。你应该尽一切努力避免变异状态。例如,不需要使用C风格的for
- 循环,而是需要更新计数器变量,使用map
和其他高阶函数来抽象出迭代模式。这也意味着如果可以避免,则永远不要更改变量的值。相反,你应该定义几乎所有变量,最好是所有变量,作为常量,并使用函数从它们计算新值而不是改变它们。
避免像瘟疫那样的副作用。
可变状态丑陋的堂兄,副作用。副作用意味着除了获取值并在函数中返回值之外的任何其他内容。如果该函数打印数据,则改变全局变量,将消息发送到线程或任何其他内容,除了简单地获取其参数,从中计算值以及返回值之外的任何其他内容,该函数都有副作用。副作用很重要(参见下一个要点),但如果你经常使用它们,就无法跟踪它们。想想每个人如何告诉你在命令式编程中避免全局变量。功能编程更进一步,试图避免所有副作用。您的程序的大部分应该由纯函数组成。 (见前)
当您需要使用副作用时,请将其保留。
是的,我刚刚告诉你要远离副作用。但是,如果没有某种副作用,没有程序是有用的。图形用户界面?副作用。音频输出?副作用。打印到外壳?副作用。因此,如果你想构建有用的东西,你就不能真正摆脱副作用。 您应该做的是编写代码,以便所有副作用代码都存在于一个薄层中,该层主要调用纯函数,然后使用这些纯函数调用的结果执行所需的副作用。
为您可以使用的所有内容使用纯函数。
这是前一点的另一面。 纯函数是一个没有副作用且不会改变任何东西的函数。它只能接受参数并返回一个值。你应该使用这些很多。例如,您应该使用纯函数构建日志字符串,然后让副作用层调用这些纯函数,调用更纯函数以格式化日志字符串,而不是在计算内容函数中进行日志记录。进入完整日志,然后从副作用层输出日志本身。
使用高阶函数构建代码。
在某种程度上,高阶函数是使函数式编程工作的粘合剂。高阶函数是将一个或多个函数作为参数和/或返回函数的函数。高阶函数的强大之处在于它们可以以声明方式封装您在命令式程序中使用的许多模式。例如,让我们来看看三个最常见的高阶函数:
map
是一个函数,它接受一个函数和一个值列表,将其函数参数应用于每个值,并返回一个包含结果的新列表。 map
封装了整个模式,迭代遍历以声明方式对每个值执行操作的列表。
filter
是一个函数,它接受一个返回布尔值和值列表的函数,将其函数参数应用于每个值并返回一个列表,该列表仅包含其函数参数返回的值{{ 1}}。它封装了以声明方式从列表中选择结果的整个模式。
true
,也称为reduce
,采用初始值,二进制函数和值列表。它使用其函数参数将初始值与列表的第一个值组合,然后将结果与列表的下一个值组合,并继续执行此操作,直到将列表缩减为单个值。它封装了从值列表中获取聚合值的整个模式。
这绝不是高阶函数的详尽列表,但这三个是最常见的函数。我希望这足以说明如何构建代码,这些代码需要大量跟踪变量,只需要以声明方式使用函数。如果您使用这些高阶函数,则可能无法再次需要fold
或for
循环。
这绝对不是 详尽的功能编程实践列表,但我认为大多数功能程序员都同意这五个指南构成了函数式编程的核心。如果你想真正学习如何应用这些,我的建议是学习一种纯函数式编程语言,比如Haskell,所以你不得不放弃命令式范式并学习如何在功能上构造事物。代替。如果你选择这样的话,我会推荐很棒的Haskell Programming from First Principles作为起始资源。如果您不想/不能放下现金,Brent Yorgey's Haskell course at UPenn也是一个很好的免费资源。