Skip to content

Instantly share code, notes, and snippets.

@elm4ward
Created December 15, 2017 12:23
Show Gist options
  • Save elm4ward/5d51d144ab2c8d9c894ab90ed3cd92a7 to your computer and use it in GitHub Desktop.
Save elm4ward/5d51d144ab2c8d9c894ab90ed3cd92a7 to your computer and use it in GitHub Desktop.
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