Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 42 additions & 27 deletions Functors-Applicatives-Monads-In-Pictures.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@



//: This is a companion Playground for the article "Swift Functors, Applicatives, and Monads in Pictures", available at http://www.mokacoding.com/blog/functor-applicative-monads-in-pictures/
//: The article itself is a translation of the original "Functors, Applicatives, and Monads in Pictures" written for Haskell by Aditya Bhargava, available at http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
//:
Expand All @@ -18,42 +21,43 @@ func plusThree(addend: Int) -> Int {
return addend + 3
}

Optional.Some(2).map(plusThree)
Optional.some(2).map(plusThree)

//: We can use autoclosures and be more succint

Optional.Some(2).map { $0 + 3 }
Optional.some(2).map { $0 + 3 }

//: If the optional value is .None, map will return .None (nil)

Optional.None.map { $0 + 3 }
Optional.none.map { $0 + 3 }

//: Map implementation might look like this

func myMap<T, U>(a: T?, f: T -> U) -> U? {
func myMap<T, U>(a: T?, f: (T) -> U) -> U? {
switch a {
case .Some(let x): return f(x)
case .None: return .None
case .some(let x): return f(x)
case .none: return .none
}
}

myMap(Optional.Some(2), f: { $0 + 3 })
myMap(a: Optional.some(2), f: { $0 + 3 })

//: We can define an infix operator

infix operator <^> { associativity left }
infix operator <^>: MultiplicationPrecedence

func <^><T, U>(f: T -> U, a: T?) -> U? {
func <^><T, U>(f: (T) -> U, a: T?) -> U? {
return a.map(f)
}

plusThree <^> Optional.Some(2)
plusThree <^> Optional.some(2)

//: Turns out functions can be mapped as well. Functions are functors too!

typealias IntFunction = Int -> Int
typealias IntFunction = (Int) -> Int

func map(f: IntFunction, _ g: IntFunction) -> IntFunction {
func map(_
f: @escaping IntFunction, _ g: @escaping IntFunction) -> IntFunction {
return { x in f(g(x)) }
}

Expand All @@ -62,16 +66,17 @@ foo(10)

//: ## Applicative
extension Optional {
func apply<U>(f: (Wrapped -> U)?) -> U? {
func apply<U>(_ f: ((Wrapped) -> U)?) -> U? {
switch f {
case .Some(let someF): return self.map(someF)
case .None: return .None
case .some(let someF): return self.map(someF)
case .none: return .none
}
}
}

extension Array {
func apply<U>(fs: [Element -> U]) -> [U] {
func apply<U>(_
fs: [(Element) -> U]) -> [U] {
var result = [U]()
for f in fs {
for element in self.map(f) {
Expand All @@ -82,50 +87,60 @@ extension Array {
}
}

infix operator <*> { associativity left }
infix operator <*>: MultiplicationPrecedence

func <*><T, U>(f: (T -> U)?, a: T?) -> U? {
func <*><T, U>(f: ((T) -> U)?, a: T?) -> U? {
return a.apply(f)
}

func <*><T, U>(f: [T -> U], a: [T]) -> [U] {
func <*><T, U>(f: [(T) -> U], a: [T]) -> [U] {
return a.apply(f)
}

Optional.Some({ $0 + 3 }) <*> Optional.Some(2)
Optional.some({ $0 + 3 }) <*> Optional.some(2)

let arrayApplicative = [ { $0 + 3 }, { $0 * 2 } ] <*> [1, 2, 3]
//: _Playground (as of Xcode 7 Beta 3) doesn't seem to be happy show the result of array applications , so we'll print open the console with Cmd + Y to see it_

print(arrayApplicative)

func curriedAddition(a: Int)(b: Int) -> Int {
public func curry<A, B, C>(_ function: @escaping (A, B) -> C) -> (A) -> (B) -> C {
return { (a: A) -> (B) -> C in { (b: B) -> C in function(a, b) } }
}

func addition(a: Int, b: Int) -> Int {
return a + b
}

let curriedAddition = curry(addition)

curriedAddition(2)(3)

curriedAddition <^> Optional(2) <*> Optional(3)

func curriedTimes(a: Int)(b: Int) -> Int {
return a * b
func multiplication(a: Int, b: Int) -> Int {
return a * b
}

let curriedTimes = curry(multiplication)

curriedTimes <^> Optional(5) <*> Optional(3)

//: ## Monads

infix operator >>- { associativity left }
infix operator >>- : MultiplicationPrecedence

func >>-<T, U>(a: T?, f: T -> U?) -> U? {
func >>-<T, U>(a: T?, f: (T) -> U?) -> U? {
return a.flatMap(f)
}

func half(a: Int) -> Int? {
return a % 2 == 0 ? a / 2 : .None
return a % 2 == 0 ? a / 2 : .none
}

Optional(3) >>- half
Optional(4) >>- half
Optional.None >>- half
Optional.none >>- half

//: We can even chain >>-

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='ios' requires-full-environment='true'>
<playground version='5.0' target-platform='ios' display-mode='rendered'>
<timeline fileName='timeline.xctimeline'/>
</playground>
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -3,72 +3,72 @@
version = "3.0">
<TimelineItems>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=31&amp;CharacterRangeLoc=733&amp;EndingColumnNumber=32&amp;EndingLineNumber=20&amp;StartingColumnNumber=1&amp;StartingLineNumber=20&amp;Timestamp=458515349.401583"
documentLocation = "#CharacterRangeLen=31&amp;CharacterRangeLoc=736&amp;EndingColumnNumber=32&amp;EndingLineNumber=23&amp;StartingColumnNumber=1&amp;StartingLineNumber=23&amp;Timestamp=504918237.830138"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=6&amp;CharacterRangeLoc=838&amp;EndingColumnNumber=30&amp;EndingLineNumber=25&amp;StartingColumnNumber=24&amp;StartingLineNumber=25&amp;Timestamp=458515349.4017"
documentLocation = "#CharacterRangeLen=6&amp;CharacterRangeLoc=841&amp;EndingColumnNumber=30&amp;EndingLineNumber=28&amp;StartingColumnNumber=24&amp;StartingLineNumber=28&amp;Timestamp=504918237.830297"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=28&amp;CharacterRangeLoc=913&amp;EndingColumnNumber=29&amp;EndingLineNumber=28&amp;StartingColumnNumber=1&amp;StartingLineNumber=28&amp;Timestamp=458515349.401781"
documentLocation = "#CharacterRangeLen=28&amp;CharacterRangeLoc=916&amp;EndingColumnNumber=29&amp;EndingLineNumber=31&amp;StartingColumnNumber=1&amp;StartingLineNumber=31&amp;Timestamp=504918237.830422"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=6&amp;CharacterRangeLoc=1148&amp;EndingColumnNumber=36&amp;EndingLineNumber=40&amp;StartingColumnNumber=30&amp;StartingLineNumber=40&amp;Timestamp=458515349.401858"
documentLocation = "#CharacterRangeLen=6&amp;CharacterRangeLoc=1156&amp;EndingColumnNumber=36&amp;EndingLineNumber=43&amp;StartingColumnNumber=30&amp;StartingLineNumber=43&amp;Timestamp=504918237.830534"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=30&amp;CharacterRangeLoc=1303&amp;EndingColumnNumber=31&amp;EndingLineNumber=49&amp;StartingColumnNumber=1&amp;StartingLineNumber=49&amp;Timestamp=458515349.401932"
documentLocation = "#CharacterRangeLen=30&amp;CharacterRangeLoc=1316&amp;EndingColumnNumber=31&amp;EndingLineNumber=52&amp;StartingColumnNumber=1&amp;StartingLineNumber=52&amp;Timestamp=504969361.521594"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=7&amp;CharacterRangeLoc=1576&amp;EndingColumnNumber=8&amp;EndingLineNumber=60&amp;StartingColumnNumber=1&amp;StartingLineNumber=60&amp;Timestamp=458515349.402004"
documentLocation = "#CharacterRangeLen=7&amp;CharacterRangeLoc=1614&amp;EndingColumnNumber=8&amp;EndingLineNumber=64&amp;StartingColumnNumber=1&amp;StartingLineNumber=64&amp;Timestamp=504969361.521784"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=6&amp;CharacterRangeLoc=2237&amp;EndingColumnNumber=23&amp;EndingLineNumber=94&amp;StartingColumnNumber=17&amp;StartingLineNumber=94&amp;Timestamp=458515390.356103"
documentLocation = "#CharacterRangeLen=6&amp;CharacterRangeLoc=2292&amp;EndingColumnNumber=23&amp;EndingLineNumber=99&amp;StartingColumnNumber=17&amp;StartingLineNumber=99&amp;Timestamp=504969374.632711"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=6&amp;CharacterRangeLoc=2296&amp;EndingColumnNumber=11&amp;EndingLineNumber=96&amp;StartingColumnNumber=5&amp;StartingLineNumber=96&amp;Timestamp=458515571.274726"
documentLocation = "#CharacterRangeLen=6&amp;CharacterRangeLoc=2351&amp;EndingColumnNumber=11&amp;EndingLineNumber=101&amp;StartingColumnNumber=5&amp;StartingLineNumber=101&amp;Timestamp=504969374.632821"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=47&amp;CharacterRangeLoc=2585&amp;EndingColumnNumber=48&amp;EndingLineNumber=105&amp;StartingColumnNumber=1&amp;StartingLineNumber=105&amp;Timestamp=458515611.936015"
documentLocation = "#CharacterRangeLen=109&amp;CharacterRangeLoc=2787&amp;EndingColumnNumber=48&amp;EndingLineNumber=118&amp;StartingColumnNumber=1&amp;StartingLineNumber=118&amp;Timestamp=504969374.632942"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=44&amp;CharacterRangeLoc=2697&amp;EndingColumnNumber=45&amp;EndingLineNumber=111&amp;StartingColumnNumber=1&amp;StartingLineNumber=111&amp;Timestamp=458515625.997398"
documentLocation = "#CharacterRangeLen=40&amp;CharacterRangeLoc=3006&amp;EndingColumnNumber=45&amp;EndingLineNumber=126&amp;StartingColumnNumber=1&amp;StartingLineNumber=126&amp;Timestamp=504969430.769491"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=20&amp;CharacterRangeLoc=2939&amp;EndingColumnNumber=21&amp;EndingLineNumber=125&amp;StartingColumnNumber=1&amp;StartingLineNumber=125&amp;Timestamp=458515783.455502"
documentLocation = "#CharacterRangeLen=20&amp;CharacterRangeLoc=3250&amp;EndingColumnNumber=21&amp;EndingLineNumber=140&amp;StartingColumnNumber=1&amp;StartingLineNumber=140&amp;Timestamp=504969475.954165"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=22&amp;CharacterRangeLoc=2981&amp;EndingColumnNumber=23&amp;EndingLineNumber=127&amp;StartingColumnNumber=1&amp;StartingLineNumber=127&amp;Timestamp=458515819.595214"
documentLocation = "#CharacterRangeLen=22&amp;CharacterRangeLoc=3292&amp;EndingColumnNumber=23&amp;EndingLineNumber=142&amp;StartingColumnNumber=1&amp;StartingLineNumber=142&amp;Timestamp=504969475.954309"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=20&amp;CharacterRangeLoc=2960&amp;EndingColumnNumber=21&amp;EndingLineNumber=126&amp;StartingColumnNumber=1&amp;StartingLineNumber=126&amp;Timestamp=458515819.595293"
documentLocation = "#CharacterRangeLen=20&amp;CharacterRangeLoc=3271&amp;EndingColumnNumber=21&amp;EndingLineNumber=141&amp;StartingColumnNumber=1&amp;StartingLineNumber=141&amp;Timestamp=504969475.95448"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
<LoggerValueHistoryTimelineItem
documentLocation = "#CharacterRangeLen=39&amp;CharacterRangeLoc=3032&amp;EndingColumnNumber=40&amp;EndingLineNumber=131&amp;StartingColumnNumber=1&amp;StartingLineNumber=131&amp;Timestamp=458515835.80059"
documentLocation = "#CharacterRangeLen=39&amp;CharacterRangeLoc=3343&amp;EndingColumnNumber=40&amp;EndingLineNumber=146&amp;StartingColumnNumber=1&amp;StartingLineNumber=146&amp;Timestamp=504969481.034319"
selectedRepresentationIndex = "0"
shouldTrackSuperviewWidth = "NO">
</LoggerValueHistoryTimelineItem>
Expand Down
Empty file modified README.md
100644 → 100755
Empty file.