Last active
August 29, 2015 14:02
-
-
Save dpwright/127314e938763920e5a5 to your computer and use it in GitHub Desktop.
First attempt at functors/monads in Swift
This file contains 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
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