Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Foundation
- import XCTest
- protocol Semiring {
- static func + (lhs: Self, rhs: Self) -> Self
- static func * (lhs: Self, rhs: Self) -> Self
- static var zero: Self { get }
- static var one: Self { get }
- }
- extension Int: Semiring {
- static let zero = 0
- static let one = 1
- }
- extension Bool: Semiring {
- static func + (lhs: Bool, rhs: Bool) -> Bool {
- return lhs || rhs
- }
- static func * (lhs: Bool, rhs: Bool) -> Bool {
- return lhs && rhs
- }
- static let zero = false
- static let one = true
- }
- struct FunctionS<A, S: Semiring> {
- let execute: (A) -> S
- init(_ execute: @escaping (A) -> S) {
- self.execute = execute
- }
- }
- extension FunctionS: Semiring {
- static func + (lhs: FunctionS, rhs: FunctionS) -> FunctionS {
- return FunctionS { lhs.execute($0) + rhs.execute($0) }
- }
- static func * (lhs: FunctionS, rhs: FunctionS) -> FunctionS {
- return FunctionS { lhs.execute($0) * rhs.execute($0) }
- }
- static var zero: FunctionS {
- return FunctionS { _ in S.zero }
- }
- static var one: FunctionS {
- return FunctionS { _ in S.one }
- }
- }
- typealias Predicate<A> = FunctionS<A, Bool>
- prefix func ! <A> (p: Predicate<A>) -> Predicate<A> {
- return .init { !p.execute($0) }
- }
- func equalTo<T: Equatable>(_ value: T) -> Predicate<T> {
- return Predicate<T> { $0 == value }
- }
- func greaterThan<T: Comparable>(_ value: T) -> Predicate<T> {
- return Predicate<T> { $0 > value }
- }
- func lessThan<T: Comparable>(_ value: T) -> Predicate<T> {
- return Predicate<T> { $0 < value }
- }
- func || <A> (lhs: Predicate<A>, rhs: Predicate<A>) -> Predicate<A> {
- return lhs + rhs
- }
- func && <A> (lhs: Predicate<A>, rhs: Predicate<A>) -> Predicate<A> {
- return lhs * rhs
- }
- lessThan(5).execute(0) // true
- extension Comparable {
- func `is`(_ predicate: Predicate<Self>) -> Bool {
- return predicate.execute(self)
- }
- }
- func between<T: Comparable>(_ a: T, and b: T) -> Predicate<T> {
- return greaterThan(a) && lessThan(b)
- }
- let valid = between(1, and: 5) && !equalTo(3)
- 1.is(valid) // false -- outside of range
- 2.is(valid) // true -- in range and not equalTo 3
- 3.is(valid) // false -- is equalTo
- 4.is(valid) // true -- in range and not equalTo 3
- 5.is(valid) // false -- outside of range
- 5.is(!valid) // true -- inverse of previous
- extension Sequence {
- func filtered(by predicate: Predicate<Element>) -> [Element] {
- return filter(predicate.execute)
- }
- }
- [0, 2, 3, 6].filtered(by: valid) // [2]
- extension FunctionS {
- func apply(_ f: @escaping (A) -> A) -> FunctionS<A, S> {
- return .init { self.execute(f($0)) }
- }
- }
- let validNegative: Predicate<Int> = valid.apply(-)
- (-2).is(validNegative) // true
- let validIfHalved = valid.apply { $0 / 2 }
- 4.is(validIfHalved) // validates 2
- let validIfDoubled = valid.apply { $0 * 2 }
- 2.is(validIfDoubled) // validates 4
- extension Comparable {
- func assert(_ predicate: Predicate<Self>, file: StaticString = #file, line: UInt = #line) {
- XCTAssertTrue(self.is(predicate), file: file, line: line)
- }
- }
- extension Sequence where Element: Comparable {
- func assert(_ predicate: Predicate<Element>, file: StaticString = #file, line: UInt = #line) {
- for element in self {
- element.assert(predicate, file: file, line: line)
- }
- }
- }
- func testMinimumIsValid() {
- 2.assert(valid) // runs single test using comparable method
- }
- func testNumbersAreValid() {
- [2, 4].assert(valid) // runs 2 tests using sequence method
- }
- func testNumbersAreInvalid() {
- [1, 3, 5].assert(!valid) // runs 3 tests using sequence method
- }
- func isNil<T>() -> Predicate<T?> {
- return Predicate { $0 == nil }
- }
- func isNotNil<T>() -> Predicate<T?> {
- return Predicate { $0 != nil }
- }
- extension Optional {
- func assert(_ predicate: Predicate<Wrapped?>, file: StaticString = #file, line: UInt = #line) {
- XCTAssertTrue(predicate.execute(self), file: file, line: line)
- }
- }
- let optional: Int? = 1
- optional.assert(!isNil())
- optional.assert(isNotNil())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement