Skip to content

Instantly share code, notes, and snippets.

@techbelly
Created February 7, 2017 23:05
Show Gist options
  • Save techbelly/c1a287bf6ed8287d825e568000dc4a3c to your computer and use it in GitHub Desktop.
Save techbelly/c1a287bf6ed8287d825e568000dc4a3c to your computer and use it in GitHub Desktop.
indirect enum Term {
case True
case False
case Zero
case Succ(Term)
case Pred(Term)
case IsZero(Term)
case If(Term, Term, Term)
}
func isNumericVal(_ t: Term) -> Bool {
switch t {
case .Zero:
return true
case .Succ(let term):
return isNumericVal(term)
default:
return false
}
}
func isVal(_ t: Term) -> Bool {
switch t {
case .True:
return true
case .False:
return true
default:
return isNumericVal(t)
}
}
enum EvalError: Error {
case NoRuleApplies(Term)
}
func eval1(_ t: Term) throws -> Term {
switch t {
case .If(.True, let t2, _):
return t2
case .If(.False, _, let t3):
return t3
case .If(let t1, let t2, let t3):
let t1_prime = try eval1(t1)
return .If(t1_prime, t2, t3)
case .Succ(let t1):
let t1_prime = try eval1(t1)
return .Succ(t1_prime)
case .Pred(.Zero):
return .Zero
case .Pred(.Succ(let nv1)) where isNumericVal(nv1):
return nv1
case .Pred(let t1):
let t1_prime = try eval1(t1)
return .Pred(t1_prime)
case .IsZero(.Zero):
return .True
case .IsZero(.Succ(let nv1)) where isNumericVal(nv1):
return .False
case .IsZero(let t1):
let t1_prime = try eval1(t1)
return .IsZero(t1_prime)
default:
throw EvalError.NoRuleApplies(t)
}
}
func eval(_ t: Term) -> Term {
do {
let t1 = try eval1(t)
return eval(t1)
} catch EvalError.NoRuleApplies(let term) {
return term
} catch {
return t
}
}
eval(.If(.IsZero(.Pred(.Succ(.Zero))), .False, .True))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment