Created
December 15, 2017 12:23
-
-
Save elm4ward/5d51d144ab2c8d9c894ab90ed3cd92a7 to your computer and use it in GitHub Desktop.
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
import Foundation | |
// contramap | |
precedencegroup I3 { associativity: left higherThan: LogicalConjunctionPrecedence } | |
precedencegroup I4 { associativity: left higherThan: LogicalConjunctionPrecedence, I3 } | |
infix operator <!> : I4 | |
let flag: (Bool) -> String = { $0 ? "β " : "β" } | |
func measure(op: () -> ()) -> Void { | |
let startTime = CFAbsoluteTimeGetCurrent() | |
op() | |
let elapsed = CFAbsoluteTimeGetCurrent() - startTime | |
print(Double(elapsed)) | |
} | |
// ------------------------ | |
// Enums | |
// ------------------------ | |
enum _PRED<I, O> { | |
case _reduceLeaf(I, (I, I) -> O) | |
indirect case _reducePred(_PRED, _PRED, (O, O) -> O) | |
case _reduceOutput((I) -> O, (I) -> O, (O, O) -> O) | |
func run(_ i: I) -> O { | |
switch self { | |
case let ._reduceLeaf(j, reduce): | |
return reduce(i, j) | |
case let ._reducePred(p, q, reduce): | |
return reduce(p.run(i), q.run(i)) | |
case let ._reduceOutput(o, p, reduce): | |
return reduce(o(i), p(i)) | |
} | |
} | |
} | |
protocol PredicateSemiring { | |
static func + (lhs: Self, rhs: Self) -> Self | |
static func * (lhs: Self, rhs: Self) -> Self | |
static var zero: Self { get } | |
static var one: Self { get } | |
} | |
// ------------------------ | |
// Predx | |
// ------------------------ | |
protocol Pred: PredicateSemiring { | |
typealias PredicateReducer<I> = _PRED<I, Self> | |
static func gt<I: Comparable>(_: I) -> PredicateReducer<I> | |
static func lt<I: Comparable>(_: I) -> PredicateReducer<I> | |
static func eq<I: Equatable>(_: I) -> PredicateReducer<I> | |
static func or<I>(_: PredicateReducer<I>, _: PredicateReducer<I>) -> PredicateReducer<I> | |
static func and<I>(_: PredicateReducer<I>, _: PredicateReducer<I>) -> PredicateReducer<I> | |
static func and<I>(_: @escaping (I) -> Self, _: @escaping (I) -> Self) -> PredicateReducer<I> | |
static func or<I>(_: @escaping (I) -> Self, _: @escaping (I) -> Self) -> PredicateReducer<I> | |
static func run<I>(_: PredicateReducer<I>) -> (I) -> Self | |
} | |
extension Pred { | |
static func or<I>(_ p1: PredicateReducer<I>, _ p2: PredicateReducer<I>) -> PredicateReducer<I> { | |
return ._reducePred(p1, p2, *) | |
} | |
static func and<I>(_ p1: PredicateReducer<I>, _ p2: PredicateReducer<I>) -> PredicateReducer<I> { | |
return ._reducePred(p1, p2, +) | |
} | |
static func and<I>(_ a: @escaping (I) -> Self, _ b: @escaping (I) -> Self) -> PredicateReducer<I> { | |
return ._reduceOutput(a, b, +) | |
} | |
static func or<I>(_ a: @escaping (I) -> Self, _ b: @escaping (I) -> Self) -> PredicateReducer<I> { | |
return ._reduceOutput(a, b, *) | |
} | |
static func run<I>(_ p: PredicateReducer<I>) -> (I) -> Self { | |
return p.run | |
} | |
} | |
// ------------------------ | |
// Bool | |
// ------------------------ | |
extension Bool: PredicateSemiring { | |
static func + (lhs: Bool, rhs: Bool) -> Bool { | |
return lhs && rhs | |
} | |
static func * (lhs: Bool, rhs: Bool) -> Bool { | |
return lhs || rhs | |
} | |
static var zero: Bool { | |
return false | |
} | |
static var one: Bool { | |
return true | |
} | |
} | |
extension Bool: Pred { | |
static func gt<I: Comparable>( _ i: I) -> PredicateReducer<I> { | |
return ._reduceLeaf(i, >) | |
} | |
static func lt<I: Comparable>( _ i: I) -> PredicateReducer<I> { | |
return ._reduceLeaf(i, <) | |
} | |
static func eq<I: Equatable>( _ i: I) -> PredicateReducer<I> { | |
return ._reduceLeaf(i, ==) | |
} | |
} | |
// ------------------------ | |
// String | |
// ------------------------ | |
extension String: PredicateSemiring { | |
static func *(lhs: String, rhs: String) -> String { | |
return lhs + " || " + rhs | |
} | |
static var zero: String { | |
return "!" | |
} | |
static var one: String { | |
return "" | |
} | |
} | |
extension String: Pred { | |
static func gt<I: Comparable>( _ i: I) -> PredicateReducer<I> { | |
return ._reduceLeaf(i, { "\($0) > \($1)" }) | |
} | |
static func lt<I: Comparable>( _ i: I) -> PredicateReducer<I> { | |
return ._reduceLeaf(i, { "\($0) < \($1)" }) | |
} | |
static func eq<I: Equatable>( _ i: I) -> PredicateReducer<I> { | |
return ._reduceLeaf(i, { "\($0) == \($1)" }) | |
} | |
} | |
// ------------------------ | |
// N | |
// ------------------------ | |
extension N: PredicateSemiring{ | |
static func +(lhs: N, rhs: N) -> N { | |
return N(s: lhs.s + rhs.s, b: lhs.b + rhs.b) | |
} | |
static func *(lhs: N, rhs: N) -> N { | |
return N(s: lhs.s * rhs.s, b: lhs.b * rhs.b) | |
} | |
static var zero: N { | |
return N(s: .zero, b: .zero) | |
} | |
static var one: N { | |
return N(s: .one, b: .one) | |
} | |
} | |
struct N: Pred { | |
let s: String | |
let b: Bool | |
static func gt<I: Comparable>( _ i: I) -> PredicateReducer<I> { | |
return ._reduceLeaf(i, { N(s:"(\($0) > \($1) [\(flag($0 > $1))])", b: $0 > $1) }) | |
} | |
static func lt<I: Comparable>( _ i: I) -> PredicateReducer<I> { | |
return ._reduceLeaf(i, { N(s:"(\($0) < \($1) [\(flag($0 < $1))])", b: $0 < $1) }) | |
} | |
static func eq<I: Equatable>( _ i: I) -> PredicateReducer<I> { | |
return ._reduceLeaf(i, { N(s:"(\($0) == \($1) [\(flag($0 == $1))])", b: $0 == $1) }) | |
} | |
} | |
// ------------------------ | |
// Sequence_Γ | |
// ------------------------ | |
extension Sequence { | |
func filter(by: IPredicate<Element, Bool>) -> [Element] { | |
return filter(by.run) | |
} | |
func filter(by: IPredicate<Element, N>) -> String { | |
return map { e in | |
let n = by.run(e) | |
let f = flag(n.b) | |
return "\(f) \(e): \n " + n.s | |
}.joined(separator: "\n ") | |
} | |
} | |
// ------------------------ | |
// IPredicate | |
// ------------------------ | |
struct IPredicate<I, O: Pred> { | |
let run: (I) -> O | |
init(_ f: @escaping (I) -> O) { | |
self.run = f | |
} | |
init<T>(_ at: KeyPath<I, T>, to: _PRED<T, O>) { | |
run = { i in | |
O.run(to)(i[keyPath: at]) | |
} | |
} | |
} | |
func && <I, O>(lhs: IPredicate<I, O>, rhs: IPredicate<I, O>) -> IPredicate<I, O> { | |
return IPredicate(O.run(O.and(lhs.run, rhs.run))) | |
} | |
func || <I, O>(lhs: IPredicate<I, O>, rhs: IPredicate<I, O>) -> IPredicate<I, O> { | |
return IPredicate(O.run(O.or(lhs.run, rhs.run))) | |
} | |
func || <I, O: Pred>(lhs: _PRED<I, O>, rhs: _PRED<I, O>) -> _PRED<I, O> { | |
return O.or(lhs, rhs) | |
} | |
func && <I, O: Pred>(lhs: _PRED<I, O>, rhs: _PRED<I, O>) -> _PRED<I, O> { | |
return O.and(lhs, rhs) | |
} | |
func gt<P: Pred, C: Comparable>(_ j: C) -> _PRED<C, P> { | |
return P.gt(j) | |
} | |
func between<P: Pred, C>(_ j: Range<C>) -> _PRED<C, P> { | |
return P.and(P.gt(j.lowerBound),P.lt(j.upperBound)) | |
} | |
func lt<P: Pred, C: Comparable>(_ j: C) -> _PRED<C, P> { | |
return P.lt(j) | |
} | |
func eq<P: Pred, C: Equatable>(_ j: C) -> _PRED<C, P> { | |
return P.eq(j) | |
} | |
func any<P: Pred, C: Equatable>(_ j: C...) -> _PRED<C, P> { | |
return j.dropFirst().reduce(P.eq(j[0])){ P.or($0, P.eq($1)) } | |
} | |
func <!> <R, V: Comparable, P: Pred>(lhs: KeyPath<R, V>, rhs: _PRED<V, P>) -> IPredicate<R, P> { | |
return IPredicate(lhs, to: rhs) | |
} | |
func == <R, V: Comparable, P: Pred>(lhs: KeyPath<R, V>, rhs: _PRED<V, P>) -> IPredicate<R, P> { | |
return IPredicate(lhs, to: rhs) | |
} | |
// ------------------------ | |
// Example | |
// ------------------------ | |
struct P: CustomStringConvertible { | |
let name: String | |
let age: Int | |
let address: A | |
var description: String { | |
return "P(name: \(name), age: \(age))" | |
} | |
} | |
struct A { | |
let country: String | |
} | |
let allPersons = [ | |
P(name: "a", age: 40, address: A(country: "π¨π¦")), | |
P(name: "a", age: 31, address: A(country: "π¬π§")), | |
P(name: "b", age: 21, address: A(country: "π©πͺ")), | |
P(name: "b", age: 50, address: A(country: "π«π·")), | |
P(name: "c", age: 60, address: A(country: "π―π΅")) | |
] | |
// Original | |
let result1 = allPersons.filter { | |
($0.age < 30 || $0.age > 20) && | |
(($0.name == "a" || $0.name == "b") || $0.address.country == "π―π΅" ) | |
} | |
// Reason | |
let result2: String = allPersons.filter(by: | |
\.age == between(20..<30) && | |
(\.name == any("a","b") || \.address.country == eq("π―π΅")) | |
) | |
// Filtered | |
let result3: [P] = allPersons.filter(by: | |
\.age == between(25..<30) && | |
(\.name == any("a","b") || \.address.country == eq("π―π΅")) | |
) | |
print("why?", "\n", result2) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment