zoukankan      html  css  js  c++  java
  • 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中,比如,下面的两个方法

    1 func intersection(region1: Region, region2: Region) -> Region { // 圆的交
    2      return { point in region1(point) && region2(point) }
    3 }
    4 func union(region1: Region, region2: Region) -> Region { // 圆的并
    5     return { point in region1(point) || region2(point) }
    6 }

    当然,我们也可以通过上面的方法去定义更加丰富的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 

      

     

      

  • 相关阅读:
    ecos 编译时无法找到 tclConfig.sh 和 tkConfig.sh
    gcc 的宏替换 __stringify
    CentOS 静态IP配置
    光照
    CUnit 安装
    git push not configured with USE_CURL_MULTI
    在VC中用FreeImage显示图片的简单方法
    vanilla kernel
    Eclipse CDT 对 Doxygen 型注释的支持
    己所不欲,人欲取之
  • 原文地址:https://www.cnblogs.com/Ohero/p/4685592.html
Copyright © 2011-2022 走看看