2016-04-04 19 views
0

düşünün:scala DSL'leri ve yazılan operatörler: deyimsel uygulama?

tüm sayısal türleri için çalışacaktır + operatörünü uygulamak için en zarif yolu nedir
// A typed Expression 
trait ExpressionT[T] extends Expression{ 
    def evaluate(): T 
} 

class Const[T<:Any](value:T) extends ExpressionT[T] { 
    def evaluate(): T = value 
} 

object Const { 
    def apply(value:Int) = new Const[Int](value) 
    def apply(value:Float) = new Const[Float](value) 
} 

:

val a:ExpressionT[Int] = Const(1) 
val b:ExpressionT[Float] = Const(2.0f) 

// + must raise types: 
// (i+i) -> i 
// (i+f) -> f 
// (f+i) -> f 
// (f+f) -> f 
val c:ExpressionT[Float] = a+b 

? Tüm tür kombinasyonlarını sıralamaktan kaçınmanın bir yolu var mı?

C'de

++ bu biz sadece (bellekten) olabilir: hayır Tür başına davaları gerektirir

template <typename T> 
class ExpressionT { 
    typedef typename T EvalT; 
    virtual T evaluate() const = 0; 
} 

// HighestType<X,Y>::EvalT,  
// (int,float) --> float 
// (float,int) --> float 
// (int,int) --> int 
template <typename X, typename Y> 
class Add : public ExpressionT< HighestType<X::EvalT, Y::EvalT>::EvalT > { 

    Add(Expression<X> const& l, Expression<X> const& r) {...} 
    inline ResultT evaluate() { return l+r; } 
} 

template <typename X, typename Y> 
auto operator + (Expression<T> const& lhs, 
        Expression<T> const& rhs){ 
    return Add(lhs, rhs); 
} 

... ayrıca mutlu + (sol eksen, rhs) tanımlı değilse derlemek başarısız olur, ve ayrıca, herhangi bir ek çalışma olmaksızın, yeni görünmeyen tiplere + (int, Matrix), + (Matrix, float) uzantıların açılmasını sağlar.

cevap

1

Böyle bir şey yapabileceğini:

implicit class ExpressionCalc[T](val it: ExpressionT[T])(implicit numeric: Numeric[T]) { 
    def +(that: ExpressionT[T]) = 
     new Const(numeric.plus(it.evaluate(), that.evaluate())) 
    } 

println(Const(5) + Const(6)) 
println(Const(5.6f) + Const(6)) 

yazık ki tam yapmak istediğiniz ne kapsamaz. Durumunuzda, argümanlardan en az birinin Float olduğu her durumda Float'u geri vermek istiyorsunuz.

Ama https://github.com/saddle/saddle/ deneyebilirsiniz, o istediğini yapmanızı sağlar:

object Const { 
    def apply(value:Int) = new Const[Int](value) 
    def apply(value:Double) = new Const[Double](value) 
    } 

    implicit class ExpressionCalc[This](val it: ExpressionT[This]) { 
    def +[That, R](that: ExpressionT[That])(implicit op: BinOp[Add, This, That, R]): ExpressionT[R] = { 
     new Const(op(it.evaluate(), that.evaluate())) 
    } 
    } 

    println(Const(5) + Const(6)) 
    println(Const(5.6) + Const(6)) 
    println(Const(5) + Const(6.7)) 

Not o eyer Float desteklememektedir, bu yüzden Double bunu değiştirdik. Ayrıca, eyer'in BinOp olduğunu nasıl uygulayacağını ve aynı yaklaşımı

kodunuzda kullanmayı deneyebilirsiniz.