Skip to content

Instantly share code, notes, and snippets.

@sebastiangrail
Created May 31, 2015 06:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sebastiangrail/828c2ad63a3ec581bf6e to your computer and use it in GitHub Desktop.
Save sebastiangrail/828c2ad63a3ec581bf6e to your computer and use it in GitHub Desktop.
Monoids on a Sunday afternoon
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