2016-04-04 12 views
0

は考えてみましょう:スカラーDSLと型付き演算子:慣用的な実装ですか?

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 

// 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) 
} 

すべての数値型のために動作します+演算子を実装するための最もエレガントな方法は何ですか?タイプのすべての組み合わせを列挙しないようにする方法はありますか? Cでは

++この我々は単に(メモリから)することができます:

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); 
} 

...何ごと型ケースを必要としないこれ、また楽しく、+(LHS、RHS)が定義されていない場合、コンパイルに失敗します。追加の作業をすることなく、新しい目に見えない型+(int、Matrix)、+(Matrix、float)への拡張を直接的に許可します。

答えて

1

あなたはこのような何かを行うことができます:

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)) 

は、残念ながら、それは完全にあなたがしたいと思うものをカバーしていません。あなたのケースでは、引数の少なくとも1つが Floatのときは常に Floatを返したいと思う。

しかし、あなたはhttps://github.com/saddle/saddle/を試すことができますが、それはあなたがやりたいことができます:

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)) 

注意をそのサドルがFloatをサポートしていないので、私はDoubleにそれを変更しました。また、サドルがどのように実装されているかを調べることもできます。BinOpと同じアプローチを使用してください。

関連する問題