Created
June 7, 2019 20:45
-
-
Save porglezomp/2e9eb8be603f0ae78071a9d5e19daf20 to your computer and use it in GitHub Desktop.
Let's do horrible crimes with overloads, in order to get Python-style comparison chaining!
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
infix operator <: ChainComparison | |
infix operator >: ChainComparison | |
infix operator ==: ChainComparison | |
infix operator !=: ChainComparison | |
infix operator <=: ChainComparison | |
infix operator >=: ChainComparison | |
precedencegroup ChainComparison { | |
associativity: left | |
} | |
struct Comparison<T: Comparable> { | |
let items: [T] | |
let comparisons: [Compare] | |
enum Compare { | |
case lt, gt, eq, ne, le, ge | |
func compare(lhs: T, rhs: T) -> Bool { | |
switch self { | |
case .lt: return lhs < rhs | |
case .gt: return lhs > rhs | |
case .eq: return lhs == rhs | |
case .ne: return lhs != rhs | |
case .le: return lhs <= rhs | |
case .ge: return lhs >= rhs | |
} | |
} | |
} | |
func eval() -> Bool { | |
for (i, op) in comparisons.enumerated() { | |
let (l, r) = (items[i], items[i+1]) | |
if !op.compare(lhs: l, rhs: r) { return false } | |
} | |
return true | |
} | |
} | |
func < <T>(lhs: T, rhs: T) -> Comparison<T> { | |
return Comparison(items: [lhs, rhs], comparisons: [.lt]) | |
} | |
func < <T>(lhs: Comparison<T>, rhs: T) -> Comparison<T> { | |
return Comparison(items: lhs.items + [rhs], comparisons: lhs.comparisons + [.lt]) | |
} | |
func < <T>(lhs: Comparison<T>, rhs: T) -> Bool { | |
return Comparison(items: lhs.items + [rhs], comparisons: lhs.comparisons + [.lt]).eval() | |
} | |
func == <T>(lhs: T, rhs: T) -> Comparison<T> { | |
return Comparison(items: [lhs, rhs], comparisons: [.eq]) | |
} | |
func == <T>(lhs: Comparison<T>, rhs: T) -> Comparison<T> { | |
return Comparison(items: lhs.items + [rhs], comparisons: lhs.comparisons + [.eq]) | |
} | |
func == <T>(lhs: Comparison<T>, rhs: T) -> Bool { | |
return Comparison(items: lhs.items + [rhs], comparisons: lhs.comparisons + [.eq]).eval() | |
} | |
let x = 2 | |
let y = 3 | |
assert(1 < x < y < 4) | |
assert(!(1 < y < x < 4)) | |
let z = x | |
assert(x == z < y == 3) | |
assert(!(1 < x == z == 3)) | |
let res: Comparison<Int> = 1 < x == z == 3 | |
print(res) | |
print(res.eval()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment