Skip to content

Instantly share code, notes, and snippets.

@alskipp
Last active February 3, 2018 22:56
Show Gist options
  • Save alskipp/3fd25ee9a92bba329b2f to your computer and use it in GitHub Desktop.
Save alskipp/3fd25ee9a92bba329b2f to your computer and use it in GitHub Desktop.
Swiftly towards the monoid
// 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
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"]
@alskipp
Copy link
Author

alskipp commented Jul 28, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment