swift 1-Functor-and-Monad.md

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了swift 1-Functor-and-Monad.md相关的知识,希望对你有一定的参考价值。

Copy and paste the swift code below into a playground to experiment.

This is a very close emulation of Functor and Monad typeclasses in swift. As of Swift 1.2 and Xcode 6.3, this is no longer very fragile.

Unfortunately, the compiler cannot verify the types when passing a function to `(>>=)`. We have to wrap the function in a closure and call it with an explicit argument to compile.

```swift
optionalDoubles >>= squareRoot // doesn't compile
optionalDoubles >>= { squareRoot($0) } // compiles
```
import Foundation

protocol Functor {
    typealias A
    typealias B
    typealias FB
    
    func fmap(A -> B) -> FB
}

protocol Monad: Functor {
    static func unit(f: A) -> Self
    func bind(f : A -> FB) -> FB
    func >>=(x: Self, f : A -> FB) -> FB
}

infix operator >>= { associativity left }
func >>=<M: Monad>(x: M, f: M.A -> M.FB) -> M.FB {
    return x.bind(f)
}
func bind<M: Monad>(x: M, f: M.A -> M.FB) -> M.FB {
    return x.bind(f)
}
func unit<M: Monad>(a: M.A) -> M {
    return M.unit(a)
}

/**
Make Array a functor
*/
extension Array: Functor {
    typealias A = T
    typealias B = Any
    typealias FB = [B]
    
    func fmap<B>(f: A -> B) -> [B] {
        return self.map(f)
    }
}

/**
Make Array a monad
*/
extension Array: Monad {
    static func unit(x: A) -> [A] {
        return [x]
    }
    
    func bind<B>(f: A -> [B]) -> [B] {
        return self.map(f).reduce([], combine: +)
    }
}

/**
Make optional a functor
*/
extension Optional: Functor {
    typealias A = T
    typealias B = Any
    typealias FB = B?
    
    func fmap<B>(f: A -> B) -> B? {
        return self.map(f)
    }
}

/**
Make optional a monad
*/
extension Optional: Monad {
    static func unit(x: A) -> A? {
        return Optional<A>.Some(x)
    }
    
    func bind<B>(f: A -> B?) -> B? {
        return self.flatMap(f)
    }
}

extension String: Functor {
    typealias A = Character
    typealias B = Character
    typealias FB = String
    
    func fmap<B>(f: A -> B) -> String {
        return "".join(self.characters.map { String(f($0) as! Character) })
    }
    
}

extension String: Monad {
    static func unit(c: A) -> String {
        return String(c)
    }
    
    func bind(f: A -> FB) -> String {
        return "".join(self.characters.map(f))
    }
}

func square(x: Double) -> Double {
    return x * x
}

func invert(x: Double) -> Double? {
    return fabs(x) > 0.0 ? 1.0 / x : nil
}

func squareRoot(x: Double) -> Double? {
    return x > 0.0 ? sqrt(x) : nil
}

func test(x: Double) -> String {
    return "test: \(x)"
}

let lettersArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz".characters.map { $0 }

func rot13(input: Character) -> Character {
    if let i = lettersArray.indexOf(input) {
        return lettersArray[i + 13 % Int(lettersArray.count)]
    } else {
        return input
    }
}

/**
Let's take Functor and Monad out for a spin...
*/

let xs = [2.0, 3.0, 5.0, 7.0, 11.0, 13.0, 17.0]
xs.fmap(square)

let optionalXs: [Double?] = [2.0, nil, 5.0, 7.0, 11.0, 13.0, 17.0]
optionalXs.fmap { $0.fmap(square) }

let optional2: Double? = 2
optional2.fmap(test)
optional2.bind(squareRoot)

optional2 >>= { squareRoot($0) }

"hello world".fmap(rot13)

"hello world" >>= { unit(rot13($0)) }

以上是关于swift 1-Functor-and-Monad.md的主要内容,如果未能解决你的问题,请参考以下文章

Swift 反射

Swift入门系列--Swift官方文档(2.2)--中文翻译--About Swift 关于Swift

swift 示例BS swift.swift

swift swift_bug.swift

ios 整理(一)swift和oc的区别

swift swift_extension5.swift