Last active
January 11, 2025 21:53
-
-
Save dabrahams/0f6e43e460256333f2fd2b7621661c0c to your computer and use it in GitHub Desktop.
A reformulation of https://gist.github.com/rxwei/e3ff811fdcaeac59bc14a034aebd4752
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
protocol NullaryFunction { | |
associatedtype Result | |
func callAsFunction() -> Result | |
} | |
protocol ExpressionResult { | |
associatedtype Expression: NullaryFunction where Expression.Result == Self; | |
} | |
typealias Expr<T: ExpressionResult> = T.Expression | |
extension Int: ExpressionResult { | |
indirect enum Expression: NullaryFunction { | |
case number(Int) | |
case arithmetic(Arithmetic<Int>, Expr<Int>, Expr<Int>) | |
func callAsFunction() -> Int { | |
switch self { | |
case .number(let r): | |
return r | |
case .arithmetic(let op, let lhs, let rhs): | |
return op(lhs(), rhs()) | |
} | |
} | |
} | |
} | |
extension Bool: ExpressionResult { | |
indirect enum Expression: NullaryFunction { | |
case bool(Bool) | |
case compare(Comparator<Int>, Expr<Int>, Expr<Int>) | |
case negate(Expr<Bool>) | |
func callAsFunction() -> Bool { | |
switch self { | |
case .bool(let r): return r | |
case .compare(let f, let lhs, let rhs): return f(lhs(), rhs()) | |
case .negate(let x): return !x() | |
} | |
} | |
} | |
} | |
/// Lifted arithmetic operators | |
enum Arithmetic<T : BinaryInteger> { | |
case add, subtract, multiply, divide | |
func callAsFunction(_ x: T, _ y: T) -> T { | |
switch self { | |
case .add: return x + y | |
case .subtract: return x - y | |
case .multiply: return x * y | |
case .divide: return x / y | |
} | |
} | |
} | |
/// Lifted comparison operators | |
enum Comparator<T : Comparable> { | |
case greaterThan, lessThan, equal | |
func callAsFunction(_ x: T, _ y: T) -> Bool { | |
switch self { | |
case .greaterThan: return x > y | |
case .lessThan: return x < y | |
case .equal: return x == y | |
} | |
} | |
} | |
/// Simple expression | |
let expr1: Expr<Bool> = .compare(.equal, .number(10), .number(30)) | |
print(expr1()) /// => false | |
let expr2: Expr<Int> = .arithmetic(.add, .number(10), .number(20)) | |
print(expr2()) /// => 30 | |
// This is an error, unlike in the other prototype. | |
//let q = Expr<Int>.bool(false) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment