Skip to content

Instantly share code, notes, and snippets.

@dpwright
Last active August 29, 2015 14:02
Show Gist options
  • Save dpwright/127314e938763920e5a5 to your computer and use it in GitHub Desktop.
Save dpwright/127314e938763920e5a5 to your computer and use it in GitHub Desktop.
First attempt at functors/monads in Swift
import Foundation
//Dumb protocols... because protocols can't (afaik) take a generic type
//parameter, I can't define functions like fmap and bind in them, which are
//pretty essential for any kind of Functor/Monad implementation, but there you
//go...
//The bits in comments demonstrate what I'd *like* to do...
protocol Functor {
typealias WrappedType
typealias SelfGeneric
//func fmap<B>(f : (A) -> B) -> SelfGeneric<B>
}
protocol Monad : Functor {
class func pure(a : WrappedType) -> Self
// func bind<A, B>(f: (A) -> SelfGeneric<B>) -> SelfGeneric<B>
}
//Obviously we don't need one of these as swift provides `optional`, but it
//makes for a good testbed...
//See the note below for an explanation about the Printable constraint on A
enum Maybe<A : Printable> {
case Nothing
case Just(A)
}
//Here's the first problem: I can't say "define Printable on Maybe<A> if A is
//Printable"... the only way I can define Printable on Maybe is by ensuring in
//the ORIGINAL DECLARATION of the Maybe<A> generic that A is Printable, which
//takes the whole point out of using an extension anyway, not to mention limits
//the types of values I can store in my new Maybe type to those which can be
//printed.
extension Maybe : Printable {
var description : String {
switch(self) {
case .Nothing: return "Nothing"
case .Just(let x1): return "Just " + x1.description
}
}
}
//Define DebugPrintable in terms of Debug
extension Maybe : DebugPrintable {
var debugDescription : String {
return self.description
}
}
extension Maybe : Functor {
typealias WrappedType = A
typealias SelfGeneric = Maybe // Doesn't work; the A is assumed implicitly it seems...
func fmap<B>(f : (A) -> B) -> Maybe<B> {
switch(self) {
case .Nothing: return Maybe<B>.Nothing
case .Just(let x1): return Maybe<B>.Just(f(x1))
}
}
}
extension Maybe : Monad {
static func pure(a : A) -> Maybe<A> {
return .Just(a)
}
func bind<B>(f: (A) -> Maybe<B>) -> Maybe<B> {
switch(self) {
case .Nothing: return Maybe<B>.Nothing
case .Just(let a1): return f(a1)
}
}
}
//We have to rewrite this for every Monad, because I can't find a way to write
//a protocol specifying "bind"
operator infix >>= {}
//func >>= <A : Monad, B : Monad> (a: A, f: (A.WrappedType)) -> B {
func >>= <A, B> (a: Maybe<A>, f: (A) -> Maybe<B>) -> Maybe<B> {
return a.bind(f);
}
println("Hello, World!")
let x = 4
let y = 2
println(x + y)
let z : Maybe<Int8> = Maybe.Nothing
let foo = Maybe.Just(16)
//It does kinda work though!
let bar = foo >>= {x in
.pure(x + 2) >>= {y in
.pure(y * 2) }}
println(bar)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment