Skip to content

Instantly share code, notes, and snippets.

@andelf
Last active February 18, 2017 00:29
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save andelf/6a8432ef0820de9991f6 to your computer and use it in GitHub Desktop.
Save andelf/6a8432ef0820de9991f6 to your computer and use it in GitHub Desktop.
Monad in Swift
// 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