[译] Bob,函数式编程是什么鬼?

本文讲的是[译] Bob,函数式编程是什么鬼?,

Bob,函数式编程是什么鬼?

写给年轻的自己的教程

老司机怎么开车,我们就怎么开

函数式编程?

你懂的。很多人都讨论它。你 Google 一下然后看了看前五篇文章,令人沮丧的是,你发现大部分文章只给出一个含糊不清的 Wikipedia 定义,像是:

“函数式编程是一种编程范式,能让你的代码清晰又明确,没有变量也没有状态。”

和你一样,老兄,事实上,我也这样搜索过。我温柔地做了个捂脸的表情,并轻声回应道:

这 TM 是啥?

先决条件

和闭包很像。如果你不理解什么是后进和关键标识,比如 $0,那你还没做好阅读这篇教程的准备。你可以暂时离开,找这里的资源来升升级。

非函数式编程

我是十万个为什么。为什么要学习函数式编程?好吧,最好的答案往往来自于历史。假设你要创建一个添加一个数组的计算器应用。

// Somewhere in ViewController

let numbers = [1, 2, 3]
var sum = 0 

for number in numbers {
 sum += number
}

没问题,但是如果我再添加一个呢?

// Somewhere in NextViewController 

let newNumbers = [4, 5, 6]
var newSum = 0

for newNumber in numbers {
 newSum += newNumber
}

这看起来就像我们重复我们自己,又长又无聊,还没必要。你不得不创建一个 sum 来记录添加的结果。这很让人崩溃,五行代码。我们最好创建一个函数代替这些玩意。

func saveMeFromMadness(elements: [Int]) -> Int {
 var sum = 0

 for element in elements {
  sum += element
 }

 return sum
}

这样在需要使用 sum 的地方,直接调用

// Somewhere in ViewController
saveMeFromMadness(elements: [1, 2, 3])

// Somewhere in NextViewController
saveMeFromMadness(elements: [4, 5, 6])

停下别动,对。你现在已经尝试了一个函数式范式的使用。函数式就是用函数来得到你想要的结果。

比喻

在 Excel 或者 Google 的 Spreadsheet 上,如果要对一些值求和,你需要选择表格,然后调用一个像是 C# 编写的函数。

Excel 里的求和函数

好,就是这样,再见。感谢阅读。 

声明式 vs 命令式

最后,现在,是时候拿出详细的函数式编程定义了。

声明式

我们经常把函数式编程描述为声明式的。你无须在意这个答案从何而来。举个例子,一个人来爬珠穆朗玛峰,可能从飞机上跳下去,也可能花好几年从地下开始爬。你会得到同样的结果。人们往往不知道 Excel 表格里的 Sum 是怎么组成的,但是,它就是得到相应的结果。

一个残酷的例子,众所周知的非函数式编程,我们经常看到上面的调用被称为命令式。它告诉你如何(how)得到从 A 到 B 的答案。

let numbers = [1, 2, 3]
var sum = 0

for number in numbers {
 sum += number
}

人们知道你循环了 numbers。但是,这有必要么?我不在意它是怎么做的,我只在意结果的出来的迅速快捷。

因此,Excel 和 Spreadsheet 融合了函数式编程的范式,来更快更简单的获取结果,而不需要关心具体的实现。(我父亲也没必要在处理公司财务数据的时候关心它)

其他的好处

在上面那个让人崩溃的例子里,我们不得不创建一个 var sum = 0 来跟踪每个视图控制器的增加结果。但是这有必要吗?sum 的值不断改变,如果我弄乱了总和怎么办?而且,我在10 条 tips 让你成为一个更好的 Swift 开发者中提到过,

更多的变量 → 更多记忆 → 更多头痛 → 更多 bug → 更多的生活问题。

更多的变量 → 容易 TM 的 → 完蛋

因此,函数式范式确保在使用的时候不可变或者没有状态的变化。

而且,和你意识到的或即将发现的一样,函数式范式提供了一个更利于维护代码的模型。

目的

那好,现在你明白了为什么我们喜欢函数式编程。所以呢?嗯,这篇教程,只专注于基本面。我不会讨论函数式编程在事件和网络等等中的应用。我可能会发一些通过 RxSwift 来做这些事的教程。所以说如果你是新手,跟着我,螺旋稳。


(译者配的图 )

真正的工作

你可能已经见过像 filtermapreduce 等等的一些东西。不错,这些让你用函数式的途径中的过滤器来处理一个数组。确保你对泛型的理解同样的酷。

这全是关于基本面的东西。如果我能教你如何在泳池里游泳,那你也可以在海里,湖里,池塘里,泥坑里(最好不是)游泳,这这篇教程,如果你学会了基本面,你就可以创建你自己的 map 和 reduce 或者其他你想要的炫酷函数。你可以 google 东西,否则,你不会从我这里得到这个叫“Bob”的开发者的解释了。

过滤器

假设你有个数组。

let recentGrade = ["A", "A", "A", "A", "B", "D"] // My College Grade

你想要过滤/带来并且返回一个只包含 “A” 的数组,这能让我妈妈感到快乐。你怎么用命令式的方式来做这个?

var happyGrade: [String] = []

for grade in recentGrade {
 if grade == "A" {
  happyGrade.append(grade)
 } else {
  print("Ma mama not happy")
 }
}

print(happyGrade) // ["A", "A", "A", "A"]

这简直让人发疯。我竟然写了这种代码。我不会在校对的时候重新检查,这很残忍。视图控制器中的8行代码?

不堪回首

我们必须停止这种疯狂,并拯救所有像你这么做的人。让我们创建一个函数来完成它。振作起来。我们现在要对付一下闭包了。让我们试着创建一个过滤器来完成和上面一样的工作。真正麻烦现在来了。

函数式的方式简介

现在我们创建一个函数,有一个包含 String 类型的数组并且有个闭包,类型是 (String) -> Bool。最后,它返回一个过滤后的 String 数组。为啥?忍我两分钟就告诉你。

func stringFilter(array: [String], returnBool: (String) -> Bool) -> [String] {}

你可能会对 returnBool 部分特别苦恼。我知道你在想什么,

那么,我们要在返回 Bool 下传递什么?

你需要创建一个闭包,包含一个 if-else 语句来判断数组里是否含有 “A”。如果有,返回true

// A closure for returnBool
let mumHappy: (String) -> Bool = { grade in return grade == "A" }

如果你想让他更短,

let mamHappy: (String) -> Bool = { $0 == "A" }

mamHappy("A") // return true
mamHappy("B") // return false

如果你对上面的两个例子感到困惑,那你还适应不了这个副本。你需要锻炼一下然后再回来。你可以重读我关于闭包的文章。链接

由于还没完成我们 stringFilter 函数的实现,让我们从离开的位置继续。

func stringFilter (grade: [String], returnBool: (String) -> Bool)-> [String] {

 var happyGrade: [String] = []
 for letter in grade {
  if returnBool(letter) {
   happyGrade.append(letter)
  }

 }
 return happyGrade
}

你的表情一定是 。我想说把刀放下,听我解释。通过 stringFilter 函数,你可以传递mamHappy 作为 returnBool。然后调用 returnBool(letter),把每个项传递个 mamHappy,最终就是 mamHappy(letter)

它返回 true 或者 false。如果返回真,把 letter 加到只有 “A” 的 happyGrade 里。

时间: 2024-09-20 08:13:06

[译] Bob,函数式编程是什么鬼?的相关文章

[译] JavaScript 的函数式编程是一种反模式

本文讲的是[译] JavaScript 的函数式编程是一种反模式, 原文地址:Functional programming in JavaScript is an antipattern 原文作者:Alex Dixon 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- 译者:sunui 校对者:LeviDing.xekri 其实 Clojure 更简单些 写了几个月 Clojure 之后我再次开始写 JavaScript.就在我试着写一些很普通的东西的时候,我

[译]跌宕起伏的函数式编程(软件编写)(第一部分)

本文讲的是[译]跌宕起伏的函数式编程(软件编写)(第一部分), 烟雾的方块艺术 -MattysFlicks -(CC BY 2.0) 注意:这是从基础学习函数式编程和使用 JavaScript ES6+ 编写软件的第一部分.保持关注,接下来还有很多! 当我 6 岁时,我花了很多时间跟我的小伙伴玩电脑游戏,他家有一个装满电脑的房间.对于我说,它们有不可抗拒的魔力.我花了很多时间探索所有的游戏.一天我问他,"我们怎样做一个游戏?" 他不知道,所以我们问了他的老爸,他的老爸爬上一个很高的架子

Guava 是个风火轮之函数式编程(3)——表处理

早先学习 Scheme 的时候,就已经对 Lisp 那行云流水般的表处理手段一见倾心.后来使用 Python 做数据处理时,语言内置的高阶函数更是得心应手.工作之后开始使用 Java,一开始的时候仿佛回到了石器时代. 直到后来我找到了 Guava,才终于又可以使用熟悉的方式去操纵集合. 函数式风格的表处理让开发者从底层的迭代处理中解放出来,从更加抽象的层面来思考问题.然而,Guava 仅仅实现了 map.filter 者两个高阶函数,并没有实现 reduce. 映射 表处理中有这样一个操作,将某

python学习(3)函数式编程

1.函数式编程(functional programming) 是一种编程方法,或者说是编程模式,它将电脑运算视为函数的计算.不需要变量因而不会产生副作用.支持高阶函数(可以接受函数作为参数). Python并不是纯的函数式编程,它允许有变量,支持闭包,有限的支持匿名函数. 与以前的C++不同的是python的变量是可以指向函数的,而函数名其实也是一个指向函数的变量. 可以看看下面的例子: f = abs f(-10) 当然我们可以想到指向函数的变量其实也可以作为函数参数,这就相当于函数作为参数

Java经典类库-Guava中的函数式编程讲解

如果我要新建一个java的项目,那么有两个类库是必备的,一个是junit,另一个是Guava.选择junit,因为我喜欢TDD,喜欢自动化测试.而是用Guava,是因为我喜欢简洁的API.Guava提供了很多的实用工具函数来弥补java标准库的不足,另外Guava还引入了函数式编程的概念,在一定程度上缓解了java在JDK1.8之前没有lambda的缺陷,使使用java书写简洁易读的函数式风格的代码成为可能. 下面就简单的介绍下Guava中的一些体现了函数式编程的API. Filter 我们先创

F#探险之旅(二):函数式编程(上)

函数式编程范式简介 F#主要支持三种编程范式:函数式编程(Functional Programming,FP).命令式编程(Imperative Programming)和面向对象(Object-Oriented,OO)的编程.回顾它们的历史,FP是最早的一种范式,第一种FP语言是IPL,产生于1955年,大约在Fortran一年之前.第二种FP语言是Lisp,产生于1958,早于Cobol一年.Fortan和Cobol都是命令式编程语言,它们在科学和商业领域的迅速成功使得命令式编程在30多年的

Guava 是个风火轮之函数式编程(1)

前言 函数式编程是一种历久弥新的编程范式,比起命令式编程,它更加关注程序的执行结果而不是执行过程.Guava 做了一些很棒的工作,搭建了在 Java 中模拟函数式编程的基础设施,让我们不用多费手脚就能享受部分函数式编程带来的便利. Java 始终是一个面向对象(命令式)的语言,在我们使用函数式编程这种黑魔法之前,需要确认:同样的功能,使用函数式编程来实现,能否在健壮性和可维护性上,超过使用面向对象(命令式)编程的实现? Function Function 接口是我们第一个介绍的 Guava 函数

基于范型的java函数式编程(一)

编程|函数 注:在您阅读本篇的时候,希望你对Java Generic(范型)能够有所了解和明白. 记:周末在给javaparty讲FP中,很多人似乎对fp并不关心,也认为java中fp的作用不大.其实这是个很大的观念错误,范型的发展,对java的函数式编程支持很大,对Functor的影响也非常大.Functor在算法.逻辑.条件计算.规则引擎等等方面,都会有很大的作为,这个影响可就会深远的多了.-- 估且以此篇的开端,唤醒java开发者对FP in Java的重新认识. 周六给javaparty

F#简明教程一:F#与函数式编程概述

F#是微软.NET开发平台的一门编程语言,其最大的特点是对函数式编程(FP,FunctionalProgramming)的引入:F#对面向对象(OOP)编程的支持也很出色,使用F#语言,开发人员可以自由选择函数式编程或面向对象编程来实现他们的项目.此外,F#还可以与.NET平台上C#.VB等其他编程语言紧密结合. CPU多核心化和云计算的背景下,函数式编程可以很好的解决多并发运算的问题(在处理并发问题方面,面向对象编程存在一定程度的固有缺陷,比如类和实例化过程中产生的一些副作用,详细请参考51C