【问题标题】:scala DSLs and typed operators: idiomatic implementation?scala DSLs 和类型化操作符:惯用的实现?
【发布时间】:2016-07-24 09:09:03
【问题描述】:

考虑:

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),无需任何额外工作。

【问题讨论】:

    标签: scala operators dsl


    【解决方案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))
    

    不幸的是,它并没有完全涵盖您想要做的事情。在您的情况下,只要至少有一个参数是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))
    

    注意,saddle 不支持Float,所以我把它改成了Double。您还可以尝试查看鞍是如何实现它的 BinOp,并在您的代码中使用相同的方法

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-21
      • 2013-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多