Last active
February 18, 2017 00:29
-
-
Save andelf/6a8432ef0820de9991f6 to your computer and use it in GitHub Desktop.
Monad in Swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Monad | |
operator infix >>= { | |
precedence 10 | |
associativity left | |
} | |
struct _MReturn { | |
} | |
@transparent func _mreturn<Args>(a: Args) -> (_MReturn, Args) { | |
return (_MReturn(), a) | |
} | |
protocol Monad { | |
typealias InnerType | |
func ~>(_: Self.InnerType, _: (_MReturn, ())) -> Self | |
func >>=(ma: Self, f: (Self.InnerType -> Self)) -> Self | |
} | |
func mreturn<M : Monad>(x: M.InnerType) -> M { | |
let (mr, arg) = _mreturn(x) | |
return x ~> (mr, ()) | |
} | |
// Monad for Array<T> | |
func >>=<T, U>(ma: Array<T>, f: (T -> Array<U>)) -> Array<U> { | |
return ma.reduce([]) { $0 + f($1) } | |
} | |
func ~><T>(a: T, _: (_MReturn, ())) -> Array<T> { | |
return [a] | |
} | |
extension Array: Monad { | |
typealias InnerType = Array.Element | |
} | |
// Monad For T? | |
func >>=<T, U>(ma: Optional<T>, f: (T -> Optional<U>)) -> Optional<U> { | |
switch ma.map(f) { | |
case .Some(let val): | |
return val | |
case .None: | |
return .None | |
} | |
} | |
func ~><T>(a: T, _: (_MReturn, ())) -> Optional<T> { | |
return Optional.Some(a) | |
} | |
extension Optional: Monad { | |
} | |
// Monad Plus | |
// mplus operator | |
operator infix +++ { | |
precedence 20 | |
associativity right | |
} | |
protocol MonadPlus: Monad { | |
class func mzero() -> Self | |
class func mplus(_: Self, _: Self) -> Self | |
} | |
func mzero<M: MonadPlus>() -> M { | |
return M.mzero() | |
} | |
func mplus<M: MonadPlus>(lhs: M, rhs: M) -> M { | |
return M.mplus(lhs, rhs) | |
} | |
func +++<M: MonadPlus>(lhs: M, rhs: M) -> M { | |
return M.mplus(lhs, rhs) | |
} | |
extension Array: MonadPlus { | |
static func mzero() -> Array { | |
return [] | |
} | |
static func mplus(lhs: Array, _ rhs: Array) -> Array { | |
return lhs + rhs | |
} | |
} | |
extension Optional: MonadPlus { | |
static func mzero() -> Optional { | |
return nil | |
} | |
static func mplus(lhs: Optional, _ rhs: Optional) -> Optional { | |
if lhs { | |
return lhs | |
} else { | |
return rhs | |
} | |
} | |
} | |
// Helper funcions | |
// sequence :: Monad m => [m a] -> m [a] | |
// func sequence<A, M: Monad, MS: Monad where M.InnerType == A, MS.InnerType == Array<A>>(ms: Array<M>) -> MS { | |
// let initial: MS = mreturn(Array<A>()) | |
// ms.reduce(initial) { | |
// (macc: MS, mx: M) -> MS in | |
// macc >>= { | |
// (acc: MS.InnerType) -> MS in | |
// mx >>= { | |
// (x: M.InnerType) -> MS in | |
// mreturn(acc + [x]) | |
// } | |
// } | |
// } | |
// } | |
// join :: (Monad m) => m (m a) -> m a | |
func join<MMA: Monad where MMA.InnerType == Monad>(x: MMA) -> MMA.InnerType { | |
return x >>= { $0 } | |
} | |
//////////////////////////////////////////////////////////////////////////////// | |
let ma: Array<Int> = mreturn(100) | |
dump(ma) | |
let b = [1, 2, 3] >>= { [$0, $0 * 100] } | |
dump(b) | |
let mc: Int? = mreturn(100) | |
dump(mc) | |
let d = mc >>= { mreturn($0 + 1000) } | |
dump(d) | |
var e: Array<String> = mzero() +++ mreturn("welcome to china") +++ mreturn("fuck") | |
dump(e, name: "MonadPlus of [String]") | |
var f: Int? = mzero() +++ mreturn(10) +++ mreturn(20) | |
dump(f, name: "MonadPlus of Optional") | |
let g = [1, 2, 3] >>= { [Double($0)] } | |
dump(g) | |
let h: String? = "23333" | |
let i: Int? = h >>= { $0.toInt() } | |
dump(i) | |
let j: String? = "233abc33" | |
let k: Int? = h >>= { $0.toInt() } | |
dump(k) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment