Skip to content

Instantly share code, notes, and snippets.

@bkase
Created January 5, 2018 06:07
Show Gist options
  • Save bkase/fe28a03c10d640ebcafa62f12430f942 to your computer and use it in GitHub Desktop.
Save bkase/fe28a03c10d640ebcafa62f12430f942 to your computer and use it in GitHub Desktop.
Reified Monoids (ported from Swift Sandbox)
// Thanks, Chris Eidhof for the idea
struct Monoid<T> {
let empty: T
let append: (T, T) -> T
func fold(arr: Array<T>) -> T {
return arr.reduce(self.empty, self.append)
}
}
let Sum = Monoid<Int>(empty: 0, append: +)
let Mul = Monoid<Int>(empty: 1, append: *)
let Max = Monoid<Int>(empty: Int.min, append: max)
func tupleMonoid<A,B>(_ ma: Monoid<A>) -> (Monoid<B>) -> Monoid<(A,B)> {
return { mb in
Monoid<(A, B)>(
empty: (ma.empty, mb.empty),
append: { (t1: (A, B), t2: (A, B)) in (ma.append(t1.0, t2.0), mb.append(t1.1, t2.1)) }
)
}
}
func funcMonoid<A,B>(_ mb: Monoid<B>) -> Monoid<(A) -> B> {
return Monoid<(A) -> B>(
empty: { _ in mb.empty },
append: { (f1: @escaping (A) -> B, f2: @escaping (A) -> B) in
{ (x: A) in
mb.append(f1(x), f2(x)) }
}
)
}
func trip<T>(x: T) -> ((T,T), T) {
return ((x,x), x)
}
print(
funcMonoid(
tupleMonoid(
tupleMonoid(Sum)(Mul)
)(Max)
)
.fold(arr: [trip, trip, trip])(3)
)
// prints ((9, 27), 3)
struct Cache<K, V> {
let get: (K) -> V?
let set: (K, V) -> Void
}
func identity<K, V>() -> Cache<K, V> {
return Cache(get: { _ in nil }, set: { k, v in })
}
func cacheMonoid<K, V>() -> Monoid<Cache<K, V>> {
return Monoid<Cache<K, V>>(
empty: identity(),
append: { (c1: Cache<K,V>, c2: Cache<K,V>) in Cache<K, V>(
get: { (k: K) in c1.get(k) ?? (
c2.get(k).map{ v in c1.set(k, v); return v }
) },
set: { (k: K, v: V) in c1.set(k, v); c2.set(k, v) }
) }
)
}
func ramCache<K, V>(name: String, dict: [K: V]) -> Cache<K, V> where K: Hashable {
var dict = dict
return Cache<K, V>(
get: { (k: K) in print("Get from \(name)"); return dict[k] },
set: { (k: K, v: V) in print("Set to \(name)"); dict[k] = v }
)
}
struct Config {
let initialState: [String: Int]
}
func c1(cfg: Config) -> Cache<String, Int> {
return ramCache(name: "c1", dict: cfg.initialState)
}
func c2(cfg: Config) -> Cache<String, Int> {
return ramCache(name: "c2", dict: [:])
}
let cache = funcMonoid(
cacheMonoid()
).fold(arr: [c2, c1])(
Config(initialState: ["foo": 3])
)
print("Cache1 \(cache.get("foo"))")
print("Cache2 \(cache.get("foo"))")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment