Skip to content

Instantly share code, notes, and snippets.

@jonhull
Last active June 11, 2016 10:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonhull/639e756ad5228348f93f40f06169588c to your computer and use it in GitHub Desktop.
Save jonhull/639e756ad5228348f93f40f06169588c to your computer and use it in GitHub Desktop.
Expression (Manual Type Erasing)
protocol Expression:CustomStringConvertible {
typealias resultType
var exprValue:resultType {get}
var hasConstantValue:Bool {get}
var isTerm:Bool {get}
func simplified()->ExpressionOf<resultType>
func exprValueWithProvider(provider:VariableProvider)->resultType
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType>
}
struct ExpressionOf<T>:Expression {
typealias resultType = T
private let _value:()->resultType
private let _valueForVars:(VariableProvider)->resultType
private let _constant:()->Bool
private let _term:()->Bool
private let _visualize:()->String
private let _simplified:(()->ExpressionOf<T>)?
private let _simplifiedForVars:((VariableProvider)->ExpressionOf<T>)?
var exprValue:resultType {return _value()}
func exprValueWithProvider(provider:VariableProvider)->resultType {return _valueForVars(provider)}
var hasConstantValue:Bool {return _constant()}
var isTerm:Bool {return _term()}
var description:String {return _visualize()}
func simplified() -> ExpressionOf<T> {return _simplified?() ?? self}
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType> {return _simplifiedForVars?(provider) ?? self}
init<E:Expression where E.resultType == T>(_ expr:E){
self._value = {expr.exprValue}
self._valueForVars = {prov in expr.exprValueWithProvider(prov)}
self._constant = {expr.hasConstantValue}
self._visualize = {expr.description}
self._simplified = {expr.simplified()}
self._simplifiedForVars = {prov in expr.simplifiedWithProvider(prov)}
self._term = {expr.isTerm}
}
init(_ exprOf:ExpressionOf<T>){
self._value = exprOf._value
self._valueForVars = exprOf._valueForVars
self._constant = exprOf._constant
self._visualize = exprOf._visualize
self._simplified = exprOf._simplified
self._simplifiedForVars = exprOf._simplifiedForVars
self._term = exprOf._term
}
init(result:T){
self._value = {result}
self._valueForVars = {prov in result}
self._constant = {true}
self._visualize = {(result as? CustomStringConvertible)?.description ?? "\(result)"}
self._simplified = nil
self._simplifiedForVars = nil
self._term = {true}
}
}
protocol ConstantExpressionTerm:Expression {}
protocol VaryingExpressionTerm:Expression {}
protocol CompoundExpression:Expression {
var subExpressions:[ExpressionOf<resultType>] {get}
}
extension Expression where Self==resultType{
var exprValue:resultType {return self}
}
extension ConstantExpressionTerm{
var hasConstantValue:Bool {return true}
var isTerm:Bool {return true}
func simplified()->ExpressionOf<resultType> {return ExpressionOf(self)}
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType> {return ExpressionOf(self)}
func exprValueWithProvider(provider:VariableProvider)->resultType {return exprValue}
}
extension VaryingExpressionTerm {
var hasConstantValue:Bool {return false}
var isTerm:Bool {return true}
func simplified()->ExpressionOf<resultType> {return ExpressionOf(self)}
}
extension CompoundExpression{
var isTerm:Bool {return false}
func simplified()->ExpressionOf<resultType> {
if self.hasConstantValue {
return ExpressionOf(result: self.exprValue)
}
return ExpressionOf(self)
}
var hasConstantValue:Bool {
return subExpressions.reduce(true, combine:{val,subExpr in val && subExpr.hasConstantValue})
}
var representsNone:Bool{
return subExpressions.reduce(true, combine: {ans,exp in ans && (exp.exprValue as? NoneRepresentable).representsNone ?? false })
}
}
//MARK: - None Representable
protocol NoneRepresentable{
var representsNone:Bool {get}
static func noneValue()->Self
}
extension Optional:NoneRepresentable {
var representsNone:Bool {
switch self{
case .None: return true
case .Some(_): return false
}
}
static func noneValue() -> Optional {
return .None
}
}
//MARK: - Operation
struct OperationExpression<T>:CompoundExpression {
typealias resultType = T
let lhs:ExpressionOf<T>
let rhs:ExpressionOf<T>
let symbol:String
let associative:Bool
let operation:(resultType,resultType)->resultType
var subExpressions:[ExpressionOf<T>] {return [lhs,rhs]}
var hasConstantValue:Bool {return lhs.hasConstantValue && rhs.hasConstantValue}
var exprValue:resultType {return operation(lhs.exprValue,rhs.exprValue)}
func exprValueWithProvider(provider:VariableProvider)->resultType {
return operation(lhs.exprValueWithProvider(provider),rhs.exprValueWithProvider(provider))
}
func simplified()->ExpressionOf<resultType> {
if self.hasConstantValue {
return ExpressionOf(result: self.exprValue)
}
return ExpressionOf(OperationExpression(lhs:lhs.simplified(), rhs:rhs.simplified(), symbol:symbol, operation:operation))
}
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType>{
if self.hasConstantValue { return ExpressionOf(result:self.exprValueWithProvider(provider)) }
let newLHS = lhs.simplifiedWithProvider(provider)
let newRHS = rhs.simplifiedWithProvider(provider)
return OperationExpression(lhs:newLHS, rhs:newRHS, symbol:symbol, operation:operation).simplified()
}
var description:String {
var left = lhs.description
var right = rhs.description
if !lhs.isTerm{
left = "(\(left))"
}
if !rhs.isTerm{
right = "(\(right))"
}
return left + " \(self.symbol) " + right
}
init(lhs:ExpressionOf<T>,rhs:ExpressionOf<T>, associative:Bool = false, symbol:String="⨀", operation:(resultType,resultType)->resultType){
self.lhs = lhs
self.rhs = rhs
self.associative = associative
self.symbol = symbol
self.operation = operation
}
init<E1:Expression, E2:Expression where E1.resultType == T, E2.resultType == T>(lhs:E1,rhs:E2, associative:Bool = false, symbol:String="⨀", operation:(resultType,resultType)->resultType){
let left = ExpressionOf(lhs)
let right = ExpressionOf(rhs)
self.init(lhs: left, rhs: right, associative:associative, symbol: symbol, operation: operation)
}
}
struct UnitaryOperationExpression<T>:Expression {
typealias resultType = T
let input:ExpressionOf<T>
let operation:(resultType)->resultType
let name:String
var exprValue:resultType {return operation(input.exprValue)}
func exprValueWithProvider(provider:VariableProvider)->resultType{return operation(input.exprValueWithProvider(provider))}
var hasConstantValue:Bool {return input.hasConstantValue}
var isTerm:Bool {return false}
func simplified()->ExpressionOf<resultType> {
if self.hasConstantValue {
return ExpressionOf(result:self.exprValue)
}
return ExpressionOf(self)
}
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType>{
if self.hasConstantValue {return ExpressionOf(result:self.exprValue)}
return UnitaryOperationExpression(input.simplifiedWithProvider(provider), name:name, operation:operation).simplified()
}
var representsNone:Bool {
if let input = input as? NoneRepresentable {
return input.representsNone
}
return false
}
var description:String {
return "\(name)(\(input.description))"
}
init(_ input:ExpressionOf<T>, name:String, operation:(T)->T) {
self.input = input
self.name = name
self.operation = operation
}
init<E:Expression where E.resultType == T>(_ expr:E, name:String, operation:(T)->T){
self.input = ExpressionOf(expr)
self.name = name
self.operation = operation
}
init (_ value:T, name:String, operation:(T)->T){
self.input = ExpressionOf(result: value)
self.name = name
self.operation = operation
}
}
struct ListOperationExpression<T>:CompoundExpression {
typealias resultType = T
let inputs:[ExpressionOf<T>]
let name:String
let operation:([resultType])->resultType
var exprValue:resultType {return operation(inputs.map({$0.exprValue}))}
func exprValueWithProvider(provider: VariableProvider) -> resultType {return operation(inputs.map({$0.exprValueWithProvider(provider)}))}
var subExpressions:[ExpressionOf<resultType>] {return inputs}
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType>{
if self.hasConstantValue {return ExpressionOf(result:self.exprValue)}
return ListOperationExpression(inputs:inputs.map({$0.simplifiedWithProvider(provider)}), name:name, operation:operation).simplified()
}
var description:String {
return name + "(" + inputs.map({$0.description}).joinWithSeparator(",") + ")"
}
}
//MARK: - Bool Expression
extension Bool:ConstantExpressionTerm{
typealias resultType = Bool
}
func boolOpForSymbol(symbol:String)->((Bool,Bool)->Bool)?{
switch symbol {
case "==","=": return (==)
case "!=","≠": return (!=)
case "&&","&","AND": return {a,b in a && b}
case "||","|","OR": return {a,b in a || b}
default: return nil
}
}
//MARK: - Int Expression
extension Int:ConstantExpressionTerm{
typealias resultType = Int
}
func intOperationExprForSymbol(symbol:String, lhs:ExpressionOf<Int>, rhs:ExpressionOf<Int>)->OperationExpression<Int>? {
switch symbol {
case "+": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:+)
case "-": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:-)
case "*","x","•": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:*)
case "/","÷": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:/)
case "%": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:%)
default: return nil
}
}
//MARK: - String Expression
extension String:ConstantExpressionTerm{
typealias resultType = String
public var description:String {return self}
}
extension String:NoneRepresentable{
var representsNone:Bool {return self.isEmpty}
static func noneValue()->String{return ""}
}
func stringOperationForSymbol(symbol:String)->((String,String)->String)? {
switch symbol {
case "+": return (+)
case "++": return {l,r in
if !(l.hasSuffix(" ") || l.hasSuffix("\n")) && !r.hasPrefix(" ") {
return l + " " + r
}
return l + r
}
default: return nil
}
}
func stringOperationExprForSymbol(symbol:String, lhs:ExpressionOf<String>, rhs:ExpressionOf<String>)->OperationExpression<String>? {
switch symbol {
case "+": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:+)
case "++": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:{l,r in
if !(l.hasSuffix(" ") || l.hasSuffix("\n")) && !r.hasPrefix(" ") {
return l + " " + r
}
return l + r
})
default: return nil
}
}
//MARK: - MathValue Expression
extension MathValue:ConstantExpressionTerm{
typealias resultType = MathValue
}
func mathOperationExprForSymbol(symbol:String, lhs:ExpressionOf<MathValue>, rhs:ExpressionOf<MathValue>)->OperationExpression<MathValue>? {
switch symbol {
case "+": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:+)
case "-": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:-)
case "*","x","•": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:*)
case "/","÷": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:/)
case "^": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation: pow)
case "%": return OperationExpression(lhs: lhs, rhs: rhs, symbol: symbol, operation:%)
default: return nil
}
}
//MARK: - Conditional Expressions
struct ConditionalExpression<T:NoneRepresentable>:Expression {
typealias resultType = T
let cond:ExpressionOf<Bool>
let expr:ExpressionOf<T>
var exprValue:resultType {
if cond.exprValue {
return expr.exprValue
}
return T.noneValue()
}
func exprValueWithProvider(provider:VariableProvider)->resultType{
if cond.exprValueWithProvider(provider){
return expr.exprValueWithProvider(provider)
}
return T.noneValue()
}
var hasConstantValue:Bool {
return cond.hasConstantValue && (!cond.exprValue || expr.hasConstantValue)
}
var isTerm:Bool {return false}
func simplified()->ExpressionOf<resultType>{
if cond.hasConstantValue {
if cond.exprValue{
return ExpressionOf(result: expr.exprValue)
}
return ExpressionOf(result: T.noneValue())
}
return ExpressionOf(self)
}
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType>{
if cond.hasConstantValue {
if cond.exprValue{
return ExpressionOf(result: expr.exprValue)
}
return ExpressionOf(result: T.noneValue())
}
return ConditionalExpression(cond:cond.simplifiedWithProvider(provider), expr:expr.simplifiedWithProvider(provider)).simplified()
}
var description:String {
return "?(" + cond.description + "): " + expr.description
}
var representsNone:Bool{
if cond.exprValue {
return exprValue.representsNone
}
return true
}
init(cond:ExpressionOf<Bool>,expr:ExpressionOf<T>){
self.cond = cond
self.expr = expr
}
init<B:Expression, E:Expression where B.resultType == Bool, E.resultType == T>(cond:B,expr:E){
self.init(cond: ExpressionOf(cond),expr:ExpressionOf(expr))
}
}
struct OptionExpression<T:NoneRepresentable>:CompoundExpression {
typealias resultType = T
let lhs:ExpressionOf<T>
let rhs:ExpressionOf<T>
let subExpressions:[ExpressionOf<T>]
var exprValue:resultType {
let left = lhs.exprValue
if left.representsNone {
return rhs.exprValue
}
return left
}
func exprValueWithProvider(provider:VariableProvider)->resultType {
let left = lhs.exprValueWithProvider(provider)
if left.representsNone {
return rhs.exprValueWithProvider(provider)
}
return left
}
func simplified()->ExpressionOf<T> {
if self.hasConstantValue {
return ExpressionOf(result: self.exprValue)
}
if lhs.hasConstantValue {
if lhs.exprValue.representsNone {
return rhs.simplified()
}
return lhs.simplified()
}
return ExpressionOf(self)
}
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType>{
if self.hasConstantValue {return ExpressionOf(result: self.exprValue)}
if lhs.hasConstantValue {
if lhs.exprValue.representsNone {
return rhs.simplifiedWithProvider(provider)
}
return lhs.simplifiedWithProvider(provider)
}
return OptionExpression(lhs:lhs.simplifiedWithProvider(provider), rhs:rhs.simplifiedWithProvider(provider)).simplified()
}
var description:String {
return lhs.description + " | " + rhs.description
}
var representsNone:Bool{
return lhs.exprValue.representsNone && rhs.exprValue.representsNone
}
init(lhs:ExpressionOf<T>,rhs:ExpressionOf<T>){
self.lhs = lhs
self.rhs = rhs
self.subExpressions = [lhs,rhs]
}
init<E1:Expression, E2:Expression where E1.resultType == T, E2.resultType == T>(lhs:E1,rhs:E2){
let left = ExpressionOf(lhs)
let right = ExpressionOf(rhs)
self.init(lhs: left, rhs: right)
}
}
struct ComparisonExpression<T:Comparable>:Expression {
typealias resultType = Bool
let lhs:ExpressionOf<T>
let rhs:ExpressionOf<T>
let comparison:String
var isTerm:Bool {return false}
func simplified()->ExpressionOf<resultType> {
if self.hasConstantValue {
return ExpressionOf(result: self.exprValue)
}
return ExpressionOf(self)
}
func simplifiedWithProvider(provider: VariableProvider) -> ExpressionOf<resultType> {
if self.hasConstantValue{
return ExpressionOf(result: self.exprValueWithProvider(provider))
}
let left = lhs.simplifiedWithProvider(provider)
let right = rhs.simplifiedWithProvider(provider)
return ExpressionOf(ComparisonExpression(lhs:left , rhs: right, comparison: comparison))
}
var hasConstantValue:Bool {
return lhs.hasConstantValue && rhs.hasConstantValue
}
var representsNone:Bool{
return false
}
var exprValue:resultType {
switch comparison{
case "=","==": return lhs.exprValue == rhs.exprValue
case "<": return lhs.exprValue < rhs.exprValue
case ">": return lhs.exprValue > rhs.exprValue
case "≤","<=": return lhs.exprValue <= rhs.exprValue
case "≥",">=": return lhs.exprValue >= rhs.exprValue
case "≠","!=": return lhs.exprValue != rhs.exprValue
default: return false
}
}
func exprValueWithProvider(provider: VariableProvider) -> resultType {
switch comparison{
case "=","==": return lhs.exprValueWithProvider(provider) == rhs.exprValueWithProvider(provider)
case "<": return lhs.exprValueWithProvider(provider) < rhs.exprValueWithProvider(provider)
case ">": return lhs.exprValueWithProvider(provider) > rhs.exprValueWithProvider(provider)
case "≤","<=": return lhs.exprValueWithProvider(provider) <= rhs.exprValueWithProvider(provider)
case "≥",">=": return lhs.exprValueWithProvider(provider) >= rhs.exprValueWithProvider(provider)
case "≠","!=": return lhs.exprValueWithProvider(provider) != rhs.exprValueWithProvider(provider)
default: return false
}
}
var description:String{
return "\(lhs) \(comparison) \(rhs)"
}
init(lhs:ExpressionOf<T>,rhs:ExpressionOf<T>, comparison:String){
self.lhs = lhs
self.rhs = rhs
self.comparison = comparison
}
init<E1:Expression, E2:Expression where E1.resultType == T, E2.resultType == T>(lhs:E1,rhs:E2,comparison:String){
let left = ExpressionOf(lhs)
let right = ExpressionOf(rhs)
self.init(lhs: left, rhs: right, comparison: comparison)
}
}
//MARK: - Adapter
struct ExpressionAdapter<In,Out>:Expression {
typealias resultType = Out
let expr:ExpressionOf<In>
let converter:(In)->Out
var exprValue:resultType {
return converter(expr.exprValue)
}
func exprValueWithProvider(provider:VariableProvider)->resultType{
return converter(expr.exprValueWithProvider(provider))
}
var hasConstantValue:Bool {return expr.hasConstantValue}
var isTerm:Bool {return expr.isTerm}
func simplified() -> ExpressionOf<resultType> {
if self.hasConstantValue {
return ExpressionOf(result: self.exprValue)
}
return ExpressionOf<resultType>(self)
}
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType>{
if self.hasConstantValue {return ExpressionOf(result: self.exprValue)}
return ExpressionAdapter(expr.simplifiedWithProvider(provider), converter:converter).simplified()
}
var description:String {
let tName = String(resultType)
return "\(tName)(\(expr.description))"
}
init(_ expr:ExpressionOf<In>, converter:(In)->Out) {
self.expr = expr
self.converter = converter
}
init<E:Expression where E.resultType == In>(_ expr:E, converter:(In)->Out){
self.expr = ExpressionOf(expr)
self.converter = converter
}
init (_ expr:In, converter:(In)->Out){
self.expr = ExpressionOf(result: expr)
self.converter = converter
}
}
struct ApplyExpression<T,Out>:Expression {
typealias resultType = Out
var value:ExpressionOf<T>
var apply:(T)->ExpressionOf<Out>
var exprValue:resultType {return apply(value.exprValue).exprValue}
func exprValueWithProvider(provider:VariableProvider)->resultType{return apply(value.exprValueWithProvider(provider)).exprValueWithProvider(provider)}
var hasConstantValue:Bool {return value.hasConstantValue}
var isTerm:Bool {return false}
func simplified()->ExpressionOf<resultType> {
if value.hasConstantValue{
return apply(value.exprValue)
}
if self.hasConstantValue {
return ExpressionOf(result:self.exprValue)
}
return ExpressionOf(self)
}
func simplifiedWithProvider(provider:VariableProvider)->ExpressionOf<resultType>{
if self.hasConstantValue {return ExpressionOf(result:self.exprValue)}
return ExpressionOf(ApplyExpression(value.simplifiedWithProvider(provider), apply:apply))
}
var description:String {
return "apply(\(value.description))"
}
init(_ value:ExpressionOf<T>, apply:(T)->ExpressionOf<Out>){
self.value = value
self.apply = apply
}
init<E:Expression where E.resultType == T>(_ valueExpr:E, apply:(T)->ExpressionOf<Out>){
self.value = ExpressionOf(valueExpr)
self.apply = apply
}
init(_ value:T, apply:(T)->ExpressionOf<Out>){
self.value = ExpressionOf(result: value)
self.apply = apply
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment