Skip to content

Instantly share code, notes, and snippets.

@dabrahams
Last active January 11, 2025 21:53
Show Gist options
  • Save dabrahams/0f6e43e460256333f2fd2b7621661c0c to your computer and use it in GitHub Desktop.
Save dabrahams/0f6e43e460256333f2fd2b7621661c0c to your computer and use it in GitHub Desktop.
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