|
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)) } |