函数式编程的前世今生
一等函数的理念可以追溯到 Church 的 lambda 演算 (Church 1941; Barendregt
1984)。此后,包括 Haskell,OCaml,Standard ML,Scala 和 F# 在内的大量 (函数式) 编程语言都不同程度地借鉴了这个概念。
OC中的一等函数 是 blocks
Swift 中就是闭包
尽管在语义上oc和swift的一等函数 完全相同,但swift的语法更加简单,使用更加方便。
例子
// hFilter.swift
// hRACDemo
//
// Created by Admin on 2016/9/20.
// Copyright © 2016年 侯迎春. All rights reserved.
//
/**
* hFilter CoreImage 滤镜相关
* API 介绍
* CIImage 图像配置
* kCIInput.. 图像处理的来源键值
* filter 图像处理 通过处理的名字 和图像来源数据
* outputImage 输出经过图像处理的图像配置源
*/
import UIKit
// 一等函数 也是一个闭包 CIImage = 图像配置
typealias hFilter = (CIImage) -> CIImage
var hycblock : (()->())?
// 模糊效果 高斯模糊
func hBlur(radius:Double) -> hFilter {
return { image in
let parameters = [kCIInputRadiusKey: radius,
kCIInputImageKey : image] as [String : AnyObject]
guard let filter = CIFilter(name: "CIGaussianBlur", withInputParameters: parameters) else {fatalError()}
guard let outputImage = filter.outputImage else {fatalError()}
return outputImage;
}
}
// Core Image 默认不包含这样一个滤 镜,但是我们完全可以用已经存在的滤镜来组成它。
// 我们将使用的两个基础组件:颜色生成滤镜 (CIConstantColorGenerator) 和图像覆盖合成滤镜 (CISourceOverCompositing)。首先让我们来定义一个生成固定颜色的滤镜
// 颜色叠层
func hColorGennerator(Color color:UIColor) -> hFilter {
return { _ in
guard let newColor : CIColor = CIColor.init(color: color) else {fatalError()}
let paramters = [kCIInputColorKey: newColor]
guard let filter = CIFilter.init(name: "CIConstantColorGenerator", withInputParameters: paramters) else{fatalError()}
guard let outputImage = filter.outputImage else {fatalError()}
return outputImage
}
}
//这段代码看起来和我们用来定义模糊滤镜的代码非常相似,但是有一个显著的区别:颜色生成 滤镜不检查输入图像。因此,我们不需要给返回函数中的图像参数命名。取而代之,我们使用 一个匿名参数 _ 来强调滤镜的输入图像参数是被忽略的。
//接下来,我们将要定义合成滤镜:
func compositeSourceOver(overlay: CIImage) -> hFilter { return { image in
let parameters = [ kCIInputBackgroundImageKey: image, kCIInputImageKey: overlay
]
guard let lter = CIFilter (name: "CISourceOverCompositing",
withInputParameters: parameters) else { fatalError() }
guard let outputImage = lter.outputImage else { fatalError() }
let cropRect = image.extent
return outputImage.imageByCroppingToRect(cropRect)
}
}
//在这里我们将输出图像剪裁为与输入图像一致的尺寸。严格来说,这不是必须的,而完全取决
//于我们希望滤镜如何工作。不过,这个选择在我们即将涉及的例子中效果很好。
//最后,我们通过结合两个滤镜来创建颜色叠层滤镜:
func colorOverlay(color:UIColor)->hFilter {
return { image in
let overlay = hColorGennerator(Color: color)(image)
return compositeSourceOver(overlay)(image)
}
}
//我们再次返回了一个接受图像作为参数的函数。colorOverlay 函数首先调用了 colorGenerator 滤镜。colorGenerator 滤镜需要一个 color 作为参数,然后返回一个新的滤镜,因此代码片段
//colorGenerator(color) 是 Filter 类型。而 Filter 类型本身就是一个从 CIImage 到 CIImage 的 函数;因此我们可以向 colorGenerator(color) 函数传递一个附加的 CIImage 类型的参数,最终 我们能够得到一个 CIImage 类型的新叠层。这就是我们在定义 overlay 的过程中所发生的全部 事情事,可以大致概括为 —— 首先使用 colorGenerator 函数创建一个滤镜,接着向这个滤镜 传递一个 image 参数来创建新图像。与之类似,返回值 compositeSourceOver(overlay)(image) 由一个通过 compositeSourceOver(overlay) 函数构建 的滤镜和随即被作为参数的 image 组成。
//复合函数
//当然,我们可以两个调用滤镜的表达式简单合为一体:
//let result = colorOverlay(overlayColor)(blur(blurRadius)(image)) 然而,由于括号错综复杂,这些代码很快失去了可读性。更好的解决方式是自定义一个运算符来组合滤镜。为了定义该运算符,首先我们要定义一个用于组合滤镜的函数:
func composeFilters( lter1: hFilter , _ lter2 : hFilter ) -> hFilter {
return { image in lter2 ( lter1 (image)) } }
//composeFilters 函数接受两个 Filter 类型的参数,并返回一个新定义的滤镜。这个复合滤镜接 受一个 CIImage 类型的图像参数,然后将该参数传递给 lter1,取得返回值之后再传递给 lter2。我们可以使用复合函数来定义复合滤镜,就像下面这样:
//let myFilter1 = composeFilters(blur(blurRadius), colorOverlay(overlayColor)) let result1 = myFilter1(image)
//为了让代码更具可读性,我们可以再进一步,为组合滤镜引入运算符。诚然,随意自定义运算
//符并不一定对提升代码可读性有帮助。不过,在图像处理库中,滤镜的组合是一个反复被讨论
//的问题,所以引入运算符极有意义:
infix operator >>> { associativity left }
func >>> ( lter1 : hFilter , lter2 : hFilter ) -> hFilter { return { image in lter2 ( lter1 (image)) }
}
//与之前使用 composeFilters 的方法相同,现在我们可以使用 >>> 运算符达到目的:
//let myFilter2 = blur(blurRadius) >>> colorOverlay(overlayColor) let result2 = myFilter2(image)
//由于已经定义的运算符 >>> 是左结合的 (left-associative),就像 Unix 的管道一样,滤镜将以从 左到右的顺序被应用到图像上。
//我们定义的组合滤镜运算符是一个复合函数的例子。在数学中,f 和 g 两个函数构成的复合函 数有时候被写作 f · g,表示定义的新函数将输入的 x 映射到 f(g(x))。除了顺序,这恰恰也是 我们的 >>> 运算符所做的:将一个图像参数传递给运算符操作的两个滤镜。