swift之函数式编程(二)
本文的主要内容来自《Functional Programming in Swift》这本书,有点所谓的观后总结
在本书的Introduction章中:
we will try to focus on some of the qualities that we believe well-designed functional programs in Swift should exhibit:
1. Modulatity【模块化】
2. A Careful Treatment of Mutable State 【细心对待可变的状态】: 不变性和无副作用
3.Types【类型】
其实上面的3点在我上篇文章已经详细介绍了。
Thinking Functionally ----- 函数式编程思想,这是本书的第二章
Functions in Swift are first-class values
下面我们根据书中的例子来阐述下本章的主要内容:
1. 判断一个Point是不是在圆心为(0,0)半径为r的圆上
typealias Position = CGPoint
typealias Distance = CGFloat
func inRange1(target: Position, range: Distance) -> Bool {
return sqrt(target.x * target.x + target.y * target.y) <= range
}
2. 判断一个点是不是在圆心不在(0,0),半径为range的圆上
func inRange2(target: Position, ownPosition: Position, range: Distance) -> Bool {
let dx = ownPosition.x - target.x
let dy = ownPosition.y - target.y
let targetDistance = sqrt(dx * dx + dy * dy)
return targetDistance <= range
}
3.判段一个Point是不是在一个圆环上。
let minimumDistance: Distance = 2.0 func inRange3(target: Position, ownPosition: Position, range: Distance) -> Bool {
let dx = ownPosition.x - target.x
let dy = ownPosition.y - target.y
let targetDistance = sqrt(dx * dx + dy * dy)
return targetDistance <= range && targetDistance >= minimumDistance
}
4. 判断一个Point是不是在圆环的grey部分,并且与一个Frendly【有点像护航船】点的距离至少为 minimumDistance
func inRange4(target: Position, ownPosition: Position, friendly: Position, range: Distance) -> Bool {
let dx = ownPosition.x - target.x
let dy = ownPosition.y - target.y
let targetDistance = sqrt(dx * dx + dy * dy)
let friendlyDx = friendly.x - target.x
let friendlyDy = friendly.y - target.y
let friendlyDistance = sqrt(friendlyDx * friendlyDx + friendlyDy * friendlyDy)
return targetDistance <= range
&& targetDistance >= minimumDistance
&& (friendlyDistance >= minimumDistance)
}
这个时候你会发现inRange这个方法是变得越来越难维持了。复杂而又臃肿的代码块。然后一起来重构:
First-Class Functions
这个问题的源头是归结于定义一个判断一个Point是不是在圆上的Function。
func pointInRange(point: Position)->Bool{
// Implement method here
}
这个方法会在以后变得越来越重要,所以我们把它取过一个单独的名字
typealias Region = Position -> Bool
从现在开始,Region 将指from a Position to a Bool的一个function,虽然这不是必要的,但他可以使得默写类型的签名更容易理解。
通过一个函数来确定一个给定的点是不是在该区域内,而不是通过类或者结构体。如果你之前没有使用过函数式编程,会看起来比较陌生,但是记住:函数在swift中第一类型值(functions in Swift are first-class values! )。决定用Region来命名这个类型,而不通过像CheckIngRegion 或者RegionBlock。因为这些名字所暗示着他们是一个函数类型,但函数式编程的关键的理念是 函数就是值,无异于Structs,intergers,booleans,使用那些具有功能性质的名字违反了这一约定。
func circle(radius: Distance) -> Region {
return { p in sqrt(p.x * p.x + p.y * p.y) <= radius }
}
当然不是所有的circle的圆心都在原点,这个时候:
func shift(offset: Position, region: Region) -> Region {
return { point in
let shiftedPoint = Position(x: point.x + offset.x, y: point.y + offset.y)
return region(shiftedPoint)
}
}
有趣的是,有很多方法去改变现有的regions。比如,我们如果想定义一个新的region通过 翻转一个region。这个最终region是当前 region之外的所有region:
func invert(region: Region) -> Region {
return { point in !region(point) }
}
当然我们也可以组合现有的region更大更复杂的region中,比如,下面的两个方法
func intersection(region1: Region, region2: Region) -> Region { // 圆的交
return { point in region1(point) && region2(point) }
}
func union(region1: Region, region2: Region) -> Region { // 圆的并
return { point in region1(point) || region2(point) }
}
当然,我们也可以通过上面的方法去定义更加丰富的region。下面的defference 函数中,有两个参数region 和 minusRegion,and constructs a region with all points that are in the first, but not in the second, region: 不在minuRegion且与region相交
func difference(region: Region, minusRegion: Region) -> Region {
return intersection(region, invert(minusRegion))
}
这些例子表明 用swift使用functions 计算和传参跟Intergers或者booleans没有区别
最后我们的inRange代码是:
func inRange(ownPosition: Position, target: Position, friendly: Position, range: Distance) -> Bool {
let rangeRegion = difference(circle(range), circle(minimumDistance))
let targetRegion = shift(ownPosition, rangeRegion)
let friendlyRegion = shift(friendly, circle(minimumDistance))
let resultRegion = difference(targetRegion, friendlyRegion)
return resultRegion(target)
}
当然这也有作者的一句话:
The way we’ve defined the Region type does have its disadvantages. In particular, we cannot inspect how a region was constructed: Is it com- posed of smaller regions? Or is it simply a circle around the origin? The only thing we can do is to check whether a given point is within a region or not. If we would want to visualize a region, we would have to sample enough points to generate a (black and white) bitmap.
Type-Driven Development
swift之函数式编程(二)的更多相关文章
- swift 之函数式编程(一)
1. 什么是函数式编程? 函数式编程是阿隆佐思想的在现实世界中的实现, 它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及异变物件. 函数式编程的最重要基础是λ演算.而且λ演算的函數可以接受函 ...
- swift之函数式编程
函数式编程初探 最近初学swift,和OC比,发现语言更现代,也有了更多的特性.如何写好swift代码,也许,熟练使用新特性写出更优秀的代码,就是答案.今天先从大的方向谈谈swift中的编程范式-函数 ...
- swift之函数式编程(四)
文章内容来自<Functional Programing in Swift>,具体内容请到书中查阅 Map, Filter, Reduce Functions that take func ...
- 最通俗易懂的方式让你理解 Swift 的函数式编程
函数式编程(Functional Programming)是相对于我们常用的面向对象和面向过程编程的另外一种开发思维方式,它更加强调以函数为中心.善用函数式编程思路,可以对我们的开发工作有很大的帮助和 ...
- js函数式编程(二)-柯里化
这节开始讲的例子都使用简单的TS来写,尽量做到和es6差别不大,正文如下 我们在编程中必然需要用到一些变量存储数据,供今后其他地方调用.而函数式编程有一个要领就是最好不要依赖外部变量(当然允许通过参数 ...
- swift之函数式编程(三)
文章来源于<Functional Programing in Swift>,本系列仅仅是观后概括的一些内容 Wrapping Core Image 上一篇文章我们介绍了 高阶函数并且展示了 ...
- swift之函数式编程(五)
文章内容来源于<Functional Programing in Swift>,详情请看原著 The Value of Immutability swift 对于控制值改变有一些机制.在这 ...
- python中函数与函数式编程(二)
首先要明白为什么要用到返回值,返回值的作用就是为了分情况来处理下面的程序(个人见解总结) 1.函数返回值 def test1(): pass def test2(): return 0 def tes ...
- Python自动化开发 - 函数式编程
本节内容 一.函数式编程 二.高阶函数 1.变量可以指向函数 2.函数名也是变量 3.传入函数 三.返回函数 1.函数作为返回值 2.闭包特性 一.函数式编程 函数是Python内建支持的一种封装,我 ...
随机推荐
- Hibernate @Embeddable注释
在hibernate中实现自定义类型,只要实现UserType接口即可或者以Component的形式提供.JPA的@Embedded注释可以在你的Entity中使用一般的Java对象,此对象需要用@E ...
- Mysql修改id自增值
如果曾经的数据都不需要的话,可以直接清空所有数据,并将自增字段恢复从1开始计数 truncate table 表名 如果想保留之前的记录,从某一id(3356)重新开始 alter table 表名 ...
- 异常 SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
使用Spring 的JDBCtemplate 调用数据库的时候 出现了如下的问题 SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-S ...
- WebService的简单介绍与入门使用
WebService是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布式 ...
- 翻译连载 | 第 9 章:递归(下)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- 基于NIO和BIO的两种服务器对比
基于BIO的服务器,服务端可能要同时保持几百万个HTTP连接,而这些连接并不是每时每刻都在传输数据,所以这种情况不适合使用BIO的服务器:而且需要保证共享资源的同步与安全,这个实现起来相对复杂.这时候 ...
- JSON和java对象的互转
先说下我自己的理解,一般而言,JSON字符串要转为java对象需要自己写一个跟JSON一模一样的实体类bean,然后用bean.class作为参数传给对应的方法,实现转化成功. 上述这种方法太麻烦了. ...
- JAVA 局部变量表
1. 除了 long,double 占用两个slot 之外,其他类型均占用一个slot. 2.在内容相同的情况下, 实例方法(不加 static) 会比 类方法 (static)对占用一个局部变量位置 ...
- 简单说明CGI是什么
html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...
- 【BZOJ】 2463 [中山市选2009]谁能赢呢?(博弈论)
Description 小明和小红经常玩一个博弈游戏.给定一个n×n的棋盘,一个石头被放在棋盘的左上角.他们轮流移动石头.每一回合,选手只能把石头向上,下,左,右四个方向移动一格,并且要求移动到的 ...