Swift功能编程 – “可选绑定”与“可选地图”

我一直在通过 Functional Programming in Swift年的书籍,并没有一个很好的方法来了解“可选”章节中介绍的一个概念的差异.

使用可选项时的模式往往是:

if let thing = optionalThing {
    return doThing(thing)
}
else {
    return nil
}

这个成语用标准库函数图简洁地处理

map(optionalThing) { thing in doThing(thing) }

然后,本书继续介绍可选绑定的概念,这就是我的区分能力开始分解的地方.

本书引导我们定义地图功能

func map<T,U>(optional: T?,f: T -> U) -> U?
{
    if let x = optional {
        return f(x)
    }
    else {
        return nil
    }
}

并指导我们定义一个可选的绑定功能.注意:本书使用运算符>> =,但是我选择使用命名函数,因为它有助于我看到相似之处.

func optionalBind<T,f: T -> U?) -> U?
{
    if let x = optional {
        return f(x)
    }
    else {
        return nil
    }
}

这两种方法的实现与我相同.两者之间唯一的区别就是它们的功能参数:

> map需要一个将T转换成U的函数
> optionalBind需要一个将T转换为可选U的函数

这些功能调用的“嵌套”结果伤害了我的大脑:

func addOptionalsBind(optionalX: Int?,optionalY: Int?) -> Int?
{
    return optionalBind(optionalX) { x in
        optionalBind(optionalY) { y in
            x + y
        }
    }
}

func addOptionalsMap(optionalX: Int?,optionalY: Int?) -> Int?
{
    return map(optionalX) { x in
        map(optionalY) { y in
            x + y
        }
    }
}

> addOptionalsBind函数完全符合你期望做的事情.
> addOptionalsMap函数无法编译说明:

‘Int??’ is not convertible to ‘Int?’


我觉得我很接近于理解这里发生了什么(可选整数被再次包装在可选中)但是如何呢?为什么?hu?),但是我还远远不够,我不完全确定一个聪明的问题要问.

通过更详细地执行addOptionalsMap,可能会更清楚.我们从最内层的地图开始,而不是你在那里,我们来改用它:
let mappedInternal: Int? = map(optionalY) { (y: Int) -> Int in
    return x + y
}

提供给映射的闭包采用Int并返回Int,而对map的调用本身返回一个可选的:Int?没有惊喜!让我们走一步,看看会发生什么:

let mappedExternal: ??? = map(optionalX) { (x: ???) -> ??? in
    let mappedInternal: Int? = map(optionalY) { (y: Int) -> Int in
        return x + y
    }
    return mappedInternal
}

这里我们可以从上面看到我们的mappedInternal值,但是还有一些类型不定义.地图具有(T 1,T→U) – >的签名. U,所以我们只需要弄清楚这种情况下T和U是什么.我们知道闭包的返回值mappedInternal是一个Int?,所以U变成Int?这里.另一方面,T可以保留不可选的Int.代替,我们得到这个:

let mappedExternal: Int?? = map(optionalX) { (x: Int) -> Int? in
    let mappedInternal: Int? = map(optionalY) { (y: Int) -> Int in
        return x + y
    }
    return mappedInternal
}

封闭物是T→ U,其评估为Int→ Int?,整个地图表达式结束映射Int?到国际?不是你所想的!

与使用optionalBind的版本对比,完全类型指定:

let boundExternal: ??? = optionalBind(optionalX) { (x: ???) -> ??? in
    let boundInternal: Int? = optionalBind(optionalY) { (y: Int) -> Int? in
        return x + y
    }
    return boundInternal
}

我们来看看那些?该版本的类型.对于optionalBind,我们需要T – > ü?关闭,并有一个Int?在boundInternal中返回值.所以在这种情况下,T和U都可以是Int,我们的实现如下所示:

let boundExternal: Int? = optionalBind(optionalX) { (x: Int) -> Int? in
    let boundInternal: Int? = optionalBind(optionalY) { (y: Int) -> Int? in
        return x + y
    }
    return boundInternal
}

您的混淆可能来自变量可以“取消”作为可选项的方式.使用单层时很容易看到:

func optionalOpposite(num: Int?) -> Int? {
    if let num = num {
        return -num
    }
    return nil
}

可以使用类型为Int的变量(如它显式期望的)或Int类型的非可选变量来调用optionalOpposite.在第二种情况下,非可选变量在调用期间被隐式转换为可选(即,解除).

地图(x:T,f:T→U)→> ü?正在提升其回报价值.由于f被声明为T – > U,它不会返回一个可选的U?然而地图的返回值为U?意味着f(x)被提升到U?回来

在你的例子中,内部关闭返回x y,这个int被提升到Int?那个值再次被提升到Int?导致类型不匹配,因为你已经声明了addOptionalsMap来返回一个Int?

相关文章

Swift 正式开源!Swift 团队很高兴宣布 Swift 开始开源新篇章。自从苹果发布 Swfit 编程语言,就成为了...
快,快,快!动动您的小手,分享给更多朋友! 苹果去年推出了全新的编程语言Swift,试图让iOS开发更简单...
开发者(KaiFaX) 面向开发者、程序员的专业平台! 和今年年初承诺的一样,苹果贴出了Swift语言的源码,...
本文由@Chun发表于Chun Tips :http://chun.tips/blog/2014/12/11/shi-yong-swift-gou-jian-zi-ding-yi...
本文由CocoaChina译者leon(社区ID)翻译 原文:THE RIGHT WAY TO WRITE A SINGLETON 在之前的帖子里聊过...
本文由CocoaChina译者leon(社区ID)翻译 原文:THE RIGHT WAY TO WRITE A SINGLETON 在之前的帖子里聊过...