Last active
February 3, 2018 22:56
-
-
Save alskipp/3fd25ee9a92bba329b2f to your computer and use it in GitHub Desktop.
Swiftly towards the monoid
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
// erm… this Num protocol is useless, but let's overlook this bit for now, shall we? | |
protocol Num: IntegerLiteralConvertible, IntegerArithmeticType {} | |
extension Int: Num {} | |
protocol Monoid { | |
static func mempty() -> Self | |
static func mappend(a: Self, _ b: Self) -> Self | |
static func mconcat(a: [Self]) -> Self | |
} | |
extension Monoid { | |
static func mconcat(a: [Self]) -> Self { | |
return a.reduce(mempty(), combine: mappend) | |
} | |
} | |
extension Array: Monoid { | |
static func mempty() -> [Element] { | |
return [] | |
} | |
static func mappend(a: [Element], _ b: [Element]) -> [Element] { | |
return a + b | |
} | |
} | |
extension String: Monoid { | |
static func mempty() -> String { | |
return "" | |
} | |
static func mappend(a: String, _ b: String) -> String { | |
return a + b | |
} | |
} | |
struct Sum<T: Num> { | |
let value: T | |
init(_ v: T) { value = v } | |
} | |
extension Sum: Monoid { | |
static func mempty() -> Sum<T> { | |
return Sum(0) | |
} | |
static func mappend(a: Sum<T>, _ b: Sum<T>) -> Sum<T> { | |
return Sum(a.value + b.value) | |
} | |
} | |
struct Product<T: Num> { | |
let value: T | |
init(_ v: T) { value = v } | |
} | |
extension Product: Monoid { | |
static func mempty() -> Product<T> { | |
return Product(1) | |
} | |
static func mappend(a: Product<T>, _ b: Product<T>) -> Product<T> { | |
return Product(a.value * b.value) | |
} | |
} | |
let a1: [Int] = .mempty() // [] | |
let a2: [Int] = .mappend([1,2],[3,4,5]) // [1,2,3,4,5] | |
let a3: [Int] = .mconcat([[1,2],[3],[4,5]]) // [1,2,3,4,5] | |
let str1: String = .mempty() // "" | |
let str2: String = .mappend("hello ", "world") // "hello world" | |
let str3: String = .mconcat(["hell", "o", " ", "world", "!"]) // "hello world!" | |
let s1: Sum<Int> = .mempty() | |
s1.value // 0 | |
let s2: Sum = .mappend(Sum(1), Sum(2)) | |
s2.value // 3 | |
let s3: Sum = .mconcat([1,2,3,4,5].map(Sum.init)) | |
s3.value // 15 | |
let p1: Product<Int> = .mempty() | |
p1.value // 1 | |
let p2: Product = .mappend(Product(2), Product(3)) | |
p2.value // 6 | |
let p3: Product = .mconcat([1,2,3,4,5].map(Product.init)) | |
p3.value // 120 |
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
infix operator >>- { associativity left precedence 150 } | |
struct Writer<W: Monoid, A> { | |
let runWriter: (value: A, log: W) | |
init(_ a: A, _ w: W) { runWriter = (a, w) } | |
} | |
func >>- <W,A,B>(x: Writer<W,A>, f: A -> Writer<W,B>) -> Writer<W,B> { | |
let (a, w) = x.runWriter | |
let (a2, w2) = f(a).runWriter | |
return Writer(a2, .mappend(w, w2)) | |
} | |
func pure<W,A>(x: A) -> Writer<W,A> { | |
return Writer(x, .mempty()) | |
} | |
func logInt(x: Int) -> Writer<[String],Int> { | |
return Writer(x, ["Got number: \(x)"]) | |
} | |
let multLog = logInt(2) >>- { a in logInt(7) >>- { b in pure(a * b) }} | |
let x = multLog.runWriter | |
x.value // 14 | |
x.log // ["Got number: 2", "Got number: 7"] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Inspired by/stolen from https://twitter.com/RuiAAPeres/status/626010701086236672