Created
May 31, 2015 06:05
-
-
Save sebastiangrail/828c2ad63a3ec581bf6e to your computer and use it in GitHub Desktop.
Monoids on a Sunday afternoon
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
protocol Monoid { | |
static func zero () -> Self | |
static func append (Self, Self) -> Self | |
} | |
protocol NumberType { | |
func add(other: Self) -> Self | |
func subtract(other: Self) -> Self | |
func multiplyWith(other: Self) -> Self | |
static func zero () -> Self | |
static func one () -> Self | |
} | |
protocol WrapperType { | |
typealias N | |
func get () -> N | |
static func construct (x: N) -> Self | |
} | |
func get <T: WrapperType> (x: T) -> T.N { | |
return x.get() | |
} | |
extension Int: NumberType { | |
func add(other: Int) -> Int { | |
return self + other | |
} | |
func subtract(other: Int) -> Int { | |
return self - other | |
} | |
func multiplyWith(other: Int) -> Int { | |
return self * other | |
} | |
static func zero() -> Int { | |
return 0 | |
} | |
static func one() -> Int { | |
return 1 | |
} | |
} | |
extension Double: NumberType { | |
func add(other: Double) -> Double { | |
return self + other | |
} | |
func subtract(other: Double) -> Double { | |
return self - other | |
} | |
func multiplyWith(other: Double) -> Double { | |
return self * other | |
} | |
static func zero() -> Double { | |
return 0.0 | |
} | |
static func one() -> Double { | |
return 1.0 | |
} | |
} | |
struct Sum <T: NumberType> : Monoid, WrapperType { | |
let value: T | |
static func zero <A> () -> Sum<A> { | |
return Sum<A>(value: A.zero()) | |
} | |
func append (other: Sum<T>) -> Sum<T> { | |
return Sum(value: self.value.add(other.value)) | |
} | |
static func append <A> (a: Sum<A>, _ b: Sum<A>) -> Sum<A> { | |
return a.append(b) | |
} | |
static func construct <A> (x: A) -> Sum<A> { | |
return Sum<A>(value: x) | |
} | |
func get () -> T { | |
return value | |
} | |
} | |
struct Product <T: NumberType> : Monoid, WrapperType { | |
let value: T | |
static func zero <A> () -> Product<A> { | |
return Product<A>(value: A.one()) | |
} | |
func append (other: Product<T>) -> Product<T> { | |
return Product(value: self.value.multiplyWith(other.value)) | |
} | |
static func append <A> (a: Product<A>, _ b: Product<A>) -> Product<A> { | |
return a.append(b) | |
} | |
static func construct <A> (x: A) -> Product<A> { | |
return Product<A>(value: x) | |
} | |
func get () -> T { | |
return value | |
} | |
} | |
struct All: Monoid, WrapperType { | |
let value: Bool | |
static func zero() -> All { | |
return All(value: true) | |
} | |
static func append(a: All, _ b: All) -> All { | |
return All(value: a.value && b.value) | |
} | |
static func construct(x: Bool) -> All { | |
return All(value: x) | |
} | |
func get () -> Bool { | |
return value | |
} | |
} | |
func mconcatenate <T: Monoid> (xs: [T]) -> T { | |
return xs.reduce(T.zero(), combine: T.append) | |
} | |
infix operator |> { associativity left } | |
func |> <T,U> (lhs: T, rhs: T -> U) -> U { | |
return rhs(lhs) | |
} | |
[1,2,3,4,5].map(Product<Int>.construct) | |
|> mconcatenate | |
|> get | |
[1.0,1.1,1.2,1.3,1.4,1.5].map(Product<Double>.construct) | |
|> mconcatenate | |
|> get | |
[true, false, true, true].map(All.construct) | |
|> mconcatenate | |
|> get | |
func satisfiesIdLaw <T: WrapperType where T.N: Equatable, T: Monoid> (x: T) -> Bool { | |
return T.append(x, T.zero()).get() == x.get() && T.append(T.zero(), x).get() == x.get() | |
} | |
func satisfiesAssociativityLaw <T: WrapperType where T.N: Equatable, T: Monoid> (a: T, b: T, c: T) -> Bool { | |
return T.append(T.append(a, b), c).get() == T.append(a, T.append(b, c)).get() | |
} | |
satisfiesIdLaw(All(value: false)) | |
satisfiesIdLaw(All(value: true)) | |
satisfiesIdLaw(Sum(value: 23)) | |
satisfiesIdLaw(Product(value: 4.5)) | |
satisfiesAssociativityLaw(Sum(value: 23), Sum(value: 42), Sum(value: 13)) | |
struct Difference <T: NumberType> : Monoid, WrapperType { | |
let value: T | |
static func zero <A> () -> Difference<A> { | |
return Difference<A>(value: A.zero()) | |
} | |
func append (other: Difference<T>) -> Difference<T> { | |
return Difference(value: self.value.subtract(other.value)) | |
} | |
static func append <A> (a: Difference<A>, _ b: Difference<A>) -> Difference<A> { | |
return a.append(b) | |
} | |
static func construct <A> (x: A) -> Difference<A> { | |
return Difference<A>(value: x) | |
} | |
func get () -> T { | |
return value | |
} | |
} | |
satisfiesIdLaw(Difference(value: 24)) | |
satisfiesAssociativityLaw(Difference(value: 23), Difference(value: 42), Difference(value: 13)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment