swift之函数式编程(三)

文章来源于《Functional Programing in Swift》,本系列仅仅是观后概括的一些内容

Wrapping Core Image

上一篇文章我们介绍了 高阶函数并且展示了函数是如何作为参数传递给其他函数。在本章中,我们将展示如何使用高阶函数对已有的 面向对象的API 进行函数式包装。

Core Image 是一个非常强大的图形处理的框架,但有些时候 它的API的使用有点笨重。CoreImage的API是松散类型—— image filters are configured using key-value coding.这样容易在类型以及参数的名称发生错误,导致运行时错误。我们新的API将会是安全和模块化的,利用类型来确保没有这样的运行时错误。

The Filter Type

CIFilter 用于创建图像过滤器(filter),当你初始化一个CIFilter对象时,你总是会提供一个输入图像通过 kCIInputImageKey,然后通过kCIOutputImageKey来获得过滤后的结果。然后您还可以用这个结果作为下个过滤器的输入。

我们将试着封装这些键值对的具体细节并提供一个安全、强类型的API给我们的用户。

typealias Filter = CIImage -> CIImage

这是我们要构建的基本类型

Building Filters

既然我们已经定义了过滤器的基本类型,我们可以开始为特定的过滤器定义相关的函数,这些便利的函数的参数需要一个特定filter和返回一个Filter。

func myFilter(/* parameters */) -> Filter

注意这个返回的Filter类型,这也是一个函数。此后,这个将帮组我们组装多个过滤器来实现我们想要的图像效果。

To make our lives a bit easier,我们将扩展CIFilter类 通过convenience initializer以及一个计算属性来取回output image

typealias Parameters = Dictionary<String, AnyObject>
extension CIFilter {
    convenience init(name: String, parameters: Parameters) {
            self.init(name: name)
            setDefaults()
            for (key, value: AnyObject) in parameters {
                setValue(value, forKey: key)
            }
    }  

    var outputImage: CIImage {
        return self.valueForKey(kCIOutputImageKey) as CIImage
    }
}

我们的便利构造器首先会调用我们的指定构造器。这个计算属性outputImage提供了一个简单的方法从filter对象中去获取output image 。通过这种计算属性,使用我们的API的用户再也不需要去关心如何获取这样的操作。

Blur(模糊)

blur filter 只需要一个blur radius 作为它的参数

func blur(radius: Double) -> Filter {
 return { image in
    let parameters: Parameters = [
        kCIInputRadiusKey: radius,
         kCIInputImageKey: image
    ]
    let filter = CIFilter(name: "CIGaussianBlur",parameters:parameters)
    return filter.outputImage
    }
}

blur function 返回一个 function,这个函数的参数是CIImage 类型的image,返回一个新的image。正因为如此,模糊函数的返回值符合我们之前定义的Filter类型

(typealias Filter = CIImage -> CIImage).这个例子我们是在原来已存在Core Image中的filter只是进行了轻包装。我们可以反复使用相同的模式来创建我们自己的过滤功能。

Color Overlay

我们定义一个过滤器:在图像上覆盖我们选定的颜色。在Core Image中默认没有这样的filter,但是我们可以,当然,这也是通过已存在的过滤器组成的。

这两个构建块是我们要用颜色生成器filter(CIConstantColorGenerator)和source-over compositing filter(CISourceOverCompositing)。

func colorGenerator(color: NSColor) -> Filter {
    return { _ in
        let parameters: Parameters = [kCIInputColorKey: color]
         let filter = CIFilter(name:"CIConstantColorGenerator",parameters: parameters)
         return filter.outputImage
    }
}

这个跟之前我们定义的blur filter相像,但有一点不同:这个constant color generator filter跟 imput image没有联系,因此我们不需要image 这个参数。

func compositeSourceOver(overlay: CIImage) -> Filter {
    return { image in
    let parameters: Parameters = [
        kCIInputBackgroundImageKey: image,
         kCIInputImageKey: overlay
        ]
    let filter = CIFilter(name: "CISourceOverCompositing",parameters: parameters)
    let cropRect = image.extent()
    return filter.outputImage.imageByCroppingToRect(cropRect) }
}

这里我们将output  image的尺寸裁剪成input image的尺寸。这不是必须的,取决于这个我们过滤器的行为。然而,在这个例子中工作的非常好。

最后,我们将两个filter进行组合成color overlay filter:

func colorOverlay(color: NSColor) -> Filter {
     return { image in
        let overlay = colorGenerator(color)(image)
        return compositeSourceOver(overlay)(image)   }
}

Composing Filters

现在我们使用我们定义的filter运用到实际的图片上:first we blur the image, and then we put a red overlay on top.

let url = NSURL(string: "http://tinyurl.com/m74sldb")
let image = CIImage(contentsOfURL: url)

// Now we can apply both filters to these by chaining them together:

let blurRadius = 5.0
let overlayColor = NSColor.redColor().colorWithAlphaComponent(0.2)
let blurredImage = blur(blurRadius)(image)
let overlaidImage = colorOverlay(overlayColor)(blurredImage)

Function Composition

当然上面的filter组合我们可以用一个语句:

let result = colorOverlay(overlayColor)(blur(blurRadius)(image))

但是,代码很快变得不可读。有一个比较好的办法就是自定义一个filter组合的操作:

func composeFilters(filter1: Filter, filter2: Filter) -> Filter {
     return { img in filter2(filter1(img)) }
}
let myFilter1 = composeFilters(blur(blurRadius), colorOverlay(overlayColor))
let result1 = myFilter1(image)

我们可以更进一步,使得这个更可读,通过自定义操作符来组合

infix operator >>> { associativity left }

func >>> (filter1: Filter, filter2: Filter) -> Filter {
    return { img in filter2(filter1(img)) }
}
let myFilter2 = blur(blurRadius) >>> colorOverlay(overlayColor)
let result2 = myFilter2(image)

当我们定义>>> 为左结合

Theoretical Background: Currying  柯里化函数

关于柯里化函数的相关知识,不多介绍,下面有相关链接:

swift的柯里化

Discussion

在这章中,我们会发现我们设计的API有这么几个优点:

1. safety----it is almost impossible to create runtime errors arising from undefined keys or failed casts

2. modularity ---it is easy to compose filters using the >>> operator.Doing so allows you to tease apart complex filters into smaller, simpler, reusable components. Additionally, composed filters have the exact same type as their building blocks, so you can use them interchangeably.

3. clarity ---- even if you have never used Core Image, you should be able to assemble simple filters using the functions we have defined. To access the results, you don’t need to know about special dictionary keys, such as kCIOutputImageKey, or worry about initializing certain keys, such as kCIInputImageKey or kCIInputRadiusKey. From the types alone, you can almost figure out how to use the API, even without further documentation

时间: 2024-10-18 08:46:02

swift之函数式编程(三)的相关文章

[Swift]以函数式编程的方式使用字符串中的Ranges

原文:Swift: Using String Ranges The Functional Way 几周之前,我介绍了『Swift中如何使用Range截取字符串』.那时,Swift中使用Range为什么如此艰难让人疑惑不解,但是至少我们找到一种可以工作的使用方法. 然而,当我在过去几周学习了许多函数式编程的知识之后,忽然意识到,Swift中的Range之所以这么难用是为了引导我们以一种更加具象的方式使用它--具体来说就是类似于函数式编程的方式. 通过观看edX FP101x课程,我学到的第一条知识

swift之函数式编程(二)------- Thinking Functionally

本文的主要内容来自<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

swift 之函数式编程(一)

1. 什么是函数式编程? 函数式编程是阿隆佐思想的在现实世界中的实现, 它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及异变物件. 函数式编程的最重要基础是λ演算.而且λ演算的函數可以接受函數當作輸入(引數)和輸出(傳出值),函數式編程更加強調程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程.函数式编程的杀手锏正是当今世界上日益增长的并行性编程和元数据编程趋势.其主要思想就是把运算过程尽量写成一系列嵌套的函数调

swift之函数式编程(四)

文章内容来自<Functional Programing in Swift>,具体内容请到书中查阅 Map, Filter, Reduce Functions that take functions as arguments are sometimes called higher- order functions. higher-order function(高阶函数)就是说函数可以作为另一个函数的参数. 在本章,我们将介绍一下swift标准库中在数组方面的一些相关的高阶函数,先介绍一些比较普

Scala 中的函数式编程基础(三)

主要来自 Scala 语言发明人 Martin Odersky 教授的 Coursera 课程 <Functional Programming Principles in Scala>. 3. Data and Abstraction 3.1 Class Hierarchies 这一集字幕不同步-,-,听得有点费力! 类的概念和其他语言里面很相似,基类,子类,父类啥的叫法差不多.在 Scala 中,所有用户自定义的类都是另外一个类的子类,如果没有显式给定父类,java 里面默认继承 java.

Swift の 函数式编程

Swift 相比原先的 Objective-C 最重要的优点之一,就是对函数式编程提供了更好的支持. Swift 提供了更多的语法糖和一些新特性来增强函数式编程的能力,本文就在这方面进行一些讨论. Swift 概览 对编程语言有了一些经验的程序员,尤其是那些对多种不同类型的编程语言都有经验的开发者, 在学习新的语言的时候更加得心应手.原因在于编程语言本身也是有各种范式的, 把握住这些特点就可以比较容易的上手了. 在入手一门新的语言的时候,一般关注的内容有: 原生数据结构 运算符 分支控制 如果是

[连载]Swift开发入门(06)--- 函数式编程

??面向对象编程和函数式编程是目前最主流的两种编程范式,而关于这两种范式孰优孰劣的讨论一直都没有停止过.事实上,真正理解两种编程范式的程序员不会武断的说这二者孰优孰劣,因为任何编程语言都没有什么灵丹妙药让其使用者成为优秀的程序员.其实,像Java这样很经典的面向对象的编程语言,也能够看到函数式编程的影子,如果你使用过访问者模式.命令模式,如果你使用过接口回调,你实际上已经使用了函数式编程的理念,而且在新版本的Java中,已经开始支持Lambda表达式和函数式接口,这些都是Java为了支持函数式编

函数式编程-将Monad(单子)融入Swift

前言 近期又开始折腾起Haskell,掉进这个深坑恐怕很难再爬上来了.在不断深入了解Haskell的各种概念以及使用它们去解决实际问题的时候,我会试想着将这些概念移植到Swift中.函数式编程范式的很多概念在Swift等主打面向对象范式的语言中就像各种设计模式一样,优雅地帮助我们构建好整个项目,促使我们的代码更加的美观优雅.安全可靠. 本篇文章为"函数式编程"系列中的第二篇,我主要说下Monad的一些小概念,以及试图将Monad融入Swift中来让其为我们的实际工程项目作出贡献. 关于

JavaScript函数式编程(三)

JavaScript函数式编程(一) JavaScript函数式编程(二) 在第二篇文章里,我们介绍了 Maybe.Either.IO 等几种常见的 Functor,或许很多看完第二篇文章的人都会有疑惑: 『这些东西有什么卵用?』 事实上,如果只是为了学习编写函数式.副作用小的代码的话,看完第一篇文章就足够了.第二篇文章和这里的第三篇着重于的是一些函数式理论的实践,是的,这些很难(但并非不可能)应用到实际的生产中,因为很多轮子都已经造好了并且很好用了.比如现在在前端大规模使用的 Promise