-
-
Save jonhull/639e756ad5228348f93f40f06169588c to your computer and use it in GitHub Desktop.
Expression (Manual Type Erasing)
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 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