Skip to content

Instantly share code, notes, and snippets.

@porglezomp
Created June 7, 2019 23:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save porglezomp/e12a170c673715f5a3b6ca2d9fe387b9 to your computer and use it in GitHub Desktop.
Save porglezomp/e12a170c673715f5a3b6ca2d9fe387b9 to your computer and use it in GitHub Desktop.
Swift has MixFix operators, right?
// Colin Barrett - @cbarrett
// turning a big dial taht says "Mixfix operators like Agda" on it
// and constantly looking back at the audience for approval
// like a contestant on the price is right
// https://twitter.com/cbarrett/status/1137113289593413633
// Here define a mixfix interpreter operator spelled: _ ⊢ ⟦_⟧
prefix operator ⟦
postfix operator ⟧
infix operator ⊢: CastingPrecedence
struct ToEval1 { let ast: Ast }
struct ToEval2 { let ast: ToEval1 }
postfix func ⟧ (ast: Ast) -> ToEval1 {
return ToEval1(ast: ast)
}
prefix func ⟦ (ast: ToEval1) -> ToEval2 {
return ToEval2(ast: ast)
}
func ⊢ (env: [Int], ast: ToEval2) -> Int {
return ast.ast.ast.eval(env: env) // :3
}
// This is a nice collection extension that I use very often
extension Collection {
subscript(safe index: Index) -> Element? {
if indices.contains(index) {
return self[index]
} else {
return nil
}
}
}
indirect enum Ast: ExpressibleByIntegerLiteral {
init(integerLiteral value: Int) {
self = .int(value)
}
typealias IntegerLiteralType = Int
case int(Int)
case `var`(Int)
case `let`(Ast, Ast)
case add(Ast, Ast), sub(Ast, Ast), mul(Ast, Ast), div(Ast, Ast), rem(Ast, Ast)
func eval(env: [Int]) -> Int {
switch self {
case .int(let val): return val
case .var(let name): return env[safe: name] ?? 0
case .let(let bind, let body): return ([env ⊢ ⟦bind⟧] + env) ⊢ ⟦body⟧
case .add(let lhs, let rhs): return (env ⊢ ⟦lhs⟧) + (env ⊢ ⟦rhs⟧)
case .sub(let lhs, let rhs): return (env ⊢ ⟦lhs⟧) - (env ⊢ ⟦rhs⟧)
case .mul(let lhs, let rhs): return (env ⊢ ⟦lhs⟧) * (env ⊢ ⟦rhs⟧)
case .div(let lhs, let rhs): return (env ⊢ ⟦lhs⟧) / (env ⊢ ⟦rhs⟧)
case .rem(let lhs, let rhs): return (env ⊢ ⟦lhs⟧) % (env ⊢ ⟦rhs⟧)
}
}
}
func + (lhs: Ast, rhs: Ast) -> Ast { return .add(lhs, rhs) }
func - (lhs: Ast, rhs: Ast) -> Ast { return .sub(lhs, rhs) }
func * (lhs: Ast, rhs: Ast) -> Ast { return .mul(lhs, rhs) }
func / (lhs: Ast, rhs: Ast) -> Ast { return .div(lhs, rhs) }
func % (lhs: Ast, rhs: Ast) -> Ast { return .rem(lhs, rhs) }
let (x, y) = (Ast.var(0), Ast.var(1))
let expr = Ast.let(20 / 2, x * x * 4 + (2 * y) - 1)
print(expr)
print([7] ⊢ ⟦expr⟧)
assert([7] ⊢ ⟦expr⟧ == 413)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment