Skip to content

Instantly share code, notes, and snippets.

@elm4ward
Last active October 23, 2023 20:30
Show Gist options
  • Save elm4ward/1d15949cfb792a6819b777b2d1ee329a to your computer and use it in GitHub Desktop.
Save elm4ward/1d15949cfb792a6819b777b2d1ee329a to your computer and use it in GitHub Desktop.
Something Bijection
// --------------------------------------------------------------------------------
// MARK: - Prerequsites
// --------------------------------------------------------------------------------
/// Compose Operator
precedencegroup BijectionGroup { associativity: left }
infix operator <> : BijectionGroup
/// Typealias for a binary function
typealias Bin<T> = (T) -> (T) -> T
/// Curry - 2nd arg - then 1st arg
func curry<A, B, C>(_ f: @escaping (A, B) -> C) -> (B) -> (A) -> C {
return { b in { a in f(a, b) } }
}
// --------------------------------------------------------------------------------
// MARK: - Bijection
// --------------------------------------------------------------------------------
struct Bijection<A, B> {
let forward: (A) -> B
let backward: (B) -> A
init(_ f: @escaping (A) -> B, _ b: @escaping (B) -> A) {
forward = f
backward = b
}
func compose<C>(_ t: Bijection<B, C>) -> Bijection<A, C> {
let f: (A) -> C = { (a: A) in t.forward(self.forward(a)) }
let b: (C) -> A = { (c: C) in self.backward(t.backward(c)) }
return Bijection<A, C>(f, b)
}
}
func <> <A, B, C>(_ lhs: Bijection<A, B>, _ rhs: Bijection<B, C>) -> Bijection<A, C> {
return lhs.compose(rhs)
}
// --------------------------------------------------------------------------------
// MARK: - In Action
// --------------------------------------------------------------------------------
let add: Bin<Double> = curry(+)
let sub: Bin<Double> = curry(-)
let mul: Bin<Double> = curry(*)
let div: Bin<Double> = curry(/)
let move: (Double) -> Bijection<Double, Double> = { Bijection(add($0), sub($0)) }
let scale: (Double) -> Bijection<Double, Double> = { Bijection(mul($0), div($0)) }
/// This is the composed bijection
let b = move(10) <> scale(5) <> move(1) <> scale(-2) <> move(100) <> scale(10)
let result1 = b.forward(2)
let result2 = b.backward(b.forward(2))
let result3 = b.forward(b.backward(b.forward(2)))
print(result1 == result3)
print(result2 == 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment