Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- let flag: (Bool) -> String = { $0 ? "✅" : "❌" }
- // ------------------------
- // Predicative
- // ------------------------
- protocol Predicative {
- static func + (lhs: Self, rhs: Self) -> Self
- static func * (lhs: Self, rhs: Self) -> Self
- static func gt<P: PredicateLike>(_: P.Input) -> P where P.Input: Comparable, P.Output == Self
- static func lt<P: PredicateLike>(_: P.Input) -> P where P.Input: Comparable, P.Output == Self
- static func eq<P: PredicateLike>(_: P.Input) -> P where P.Input: Equatable, P.Output == Self
- static func or<P: PredicateLike>(_: P, _: P) -> P where P.Output == Self
- static func and<P: PredicateLike>(_: P, _: P) -> P where P.Output == Self
- static func run<P: PredicateLike>(_: P) -> (P.Input) -> Self where P.Output == Self
- }
- extension Predicative {
- static func or<P: PredicateLike>(_ p1: P, _ p2: P) -> P where P.Output == Self {
- return .init(p1, p2, *)
- }
- static func and<P: PredicateLike>(_ p1: P, _ p2: P) -> P where P.Output == Self {
- return .init(p1, p2, +)
- }
- static func run<P: PredicateLike>(_ p: P) -> (P.Input) -> Self where P.Output == Self {
- return p.run
- }
- }
- // ------------------------
- // Predicate
- // ------------------------
- protocol PredicateLike {
- associatedtype Input
- associatedtype Output: Predicative
- init(_: Input, _: @escaping (Input, Input) -> Output)
- init(_: Self, _: Self, _: @escaping (Output, Output) -> Output)
- func run(_ i: Input) -> Output
- }
- extension PredicateLike {
- static func leaf<P>(_ i: P.Input, _ b: @escaping (P.Input, P.Input) -> P.Output) -> P where P: PredicateLike {
- return .init(i, b)
- }
- static func pred<P>(_ p1: P, _ p2: P, _ f: @escaping (P.Output, P.Output) -> P.Output) -> P where P: PredicateLike {
- return .init(p1, p2, f)
- }
- static func or<P: PredicateLike>(_ p1: P, _ p2: P) -> P {
- return P.Output.or(p1, p2)
- }
- static func and<P: PredicateLike>(_ p1: P, _ p2: P) -> P {
- return P.Output.and(p1, p2)
- }
- static func lt<P: PredicateLike>(_ i: P.Input) -> P where P.Input: Comparable {
- return P.Output.lt(i)
- }
- static func gt<P: PredicateLike>(_ i: P.Input) -> P where P.Input: Comparable {
- return P.Output.gt(i)
- }
- static func eq<P: PredicateLike>(_ i: P.Input) -> P where P.Input: Equatable {
- return P.Output.eq(i)
- }
- }
- func || <P>(lhs: P, rhs: P) -> P where P: PredicateLike {
- return .or(lhs, rhs)
- }
- func && <P>(lhs: P, rhs: P) -> P where P: PredicateLike {
- return .and(lhs, rhs)
- }
- func gt<P: PredicateLike>(_ j: P.Input) -> P where P.Input: Comparable {
- return .gt(j)
- }
- func lt<P: PredicateLike>(_ j: P.Input) -> P where P.Input: Comparable {
- return .lt(j)
- }
- func eq<P: PredicateLike>(_ j: P.Input) -> P where P.Input: Equatable {
- return .eq(j)
- }
- // ------------------------
- // PRED
- // ------------------------
- enum Predicate<I, O: Predicative>: PredicateLike {
- typealias Input = I
- typealias Output = O
- case _reduceLeaf(I, (I, I) -> O)
- indirect case _reducePred(Predicate, Predicate, (O, O) -> O)
- init(_ i: Input, _ f: @escaping (Input, Input) -> Output) {
- self = ._reduceLeaf(i, f)
- }
- init(_ p1: Predicate<I, O>, _ p2: Predicate<I, O>, _ f: @escaping (O, O) -> O) {
- self = ._reducePred(p1, p2, f)
- }
- 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))
- }
- }
- }
- // ------------------------
- // Bool
- // ------------------------
- extension Bool: Predicative {
- static func + (lhs: Bool, rhs: Bool) -> Bool {
- return lhs && rhs
- }
- static func * (lhs: Bool, rhs: Bool) -> Bool {
- return lhs || rhs
- }
- static func gt<P>(_ i: P.Input) -> P where P: PredicateLike, P.Input: Comparable, P.Output == Bool {
- return .leaf(i, >)
- }
- static func lt<P>(_ i: P.Input) -> P where P: PredicateLike, P.Input: Comparable, P.Output == Bool {
- return .leaf(i, <)
- }
- static func eq<P>(_ i: P.Input) -> P where P: PredicateLike, P.Input: Equatable, P.Output == Bool {
- return .leaf(i, ==)
- }
- }
- // ------------------------
- // String
- // ------------------------
- extension String: Predicative {
- static func * (lhs: String, rhs: String) -> String {
- return lhs + " || " + rhs
- }
- static func gt<P>(_ i: P.Input) -> P where P: PredicateLike, P.Input: Comparable, P.Output == String {
- return .leaf(i, { "\($0) > \($1)" })
- }
- static func lt<P>(_ i: P.Input) -> P where P: PredicateLike, P.Input: Comparable, P.Output == String {
- return .leaf(i, { "\($0) < \($1)" })
- }
- static func eq<P>(_ i: P.Input) -> P where P: PredicateLike, P.Input: Equatable, P.Output == String {
- return .leaf(i, { "\($0) == \($1)" })
- }
- }
- // ------------------------
- // N
- // ------------------------
- struct N: Predicative {
- let s: String
- let b: Bool
- 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 func gt<P>(_ i: P.Input) -> P where P: PredicateLike, P.Input: Comparable, P.Output == N {
- return .leaf(i, { N(s:"(\($0) > \($1) [\(flag($0 > $1))])", b: $0 > $1) })
- }
- static func lt<P>(_ i: P.Input) -> P where P: PredicateLike, P.Input: Comparable, P.Output == N {
- return .leaf(i, { N(s:"(\($0) < \($1) [\(flag($0 < $1))])", b: $0 < $1) })
- }
- static func eq<P>(_ i: P.Input) -> P where P: PredicateLike, P.Input: Equatable, P.Output == N {
- return .leaf(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)
- return "\(flag(n.b)) \(e): \n " + n.s
- }.joined(separator: "\n ")
- }
- }
- // ------------------------
- // IPredicate
- // ------------------------
- struct IPredicate<I, O: Predicative> {
- let run: (I) -> O
- init(_ f: @escaping (I) -> O) {
- self.run = f
- }
- init<P>(_ target: KeyPath<I, P>, _ predicate: Predicate<P, O>) {
- run = { i in O.run(predicate)(i[keyPath: target]) }
- }
- func liftD(_ ip: IPredicate<I, O>, _ f: @escaping (O, O) -> O) -> IPredicate<I, O> {
- return IPredicate { i in f(self.run(i), ip.run(i)) }
- }
- }
- func == <R, I, P>(lhs: KeyPath<R, I>, rhs: Predicate<I, P>) -> IPredicate<R, P> where I: Comparable {
- return IPredicate(lhs, rhs)
- }
- func && <I, O>(lhs: IPredicate<I, O>, rhs: IPredicate<I, O>) -> IPredicate<I, O> {
- return lhs.liftD(rhs, +)
- }
- func || <I, O>(lhs: IPredicate<I, O>, rhs: IPredicate<I, O>) -> IPredicate<I, O> {
- return lhs.liftD(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: "🇯🇵"))
- ]
- let result1: [P] = allPersons.filter(by:
- \.age == eq(40) || \.name == eq("a")
- )
- let result2: String = allPersons.filter(by:
- \.age == eq(40) || \.name == eq("a")
- )
- print(result2)
Add Comment
Please, Sign In to add comment