7

私は C++ から来て、scala の型システムに頭を悩ませようとしています。

次の C++ テンプレート クラスを検討してください。

template<class T>
class Point2
{
  Point2( T x, T y ) :
     x(x),
     y(y)
  {}

  T x;
  T y;
  Point2<T> operator+( Point<T> const& other ) const
  {
     return Point<T>(x+other.x, y+other.y);
  }
  T sumComponents() const { return x+y; }
}

Point2<Double> p0(12.3, 45.6) 
Point2<Double> p1(12.3, 45.6) 
Point2<Double> p = p1+p2
Double d = p1.sumComponents()

私はこのようなものを書きたいと思っています:

case class Point2[ T ] (x:T, y:T) {
   def +() Point2[T]: = x+y
   def sumComponents() T: = x+y
}

または、(コンパイルに問題があるため)、

trait Addable[T] {   // Require T supports the + operatory
   def +( that:T ):T
}
case class Point2[ T<:Addable[T] ] (x:T, y:T) {
   def +() Point2[T]: = x+y
   def sumComponents() T: = x+y
}

Addable を拡張するために Double を要求できないため、これも同様に問題があります。

一般的に、scala の型システムは、私がよく理解していない一連の制約で機能することがわかっています。

上記をscalaで実装する慣用的な方法は何ですか?

また、C++ テンプレート プログラマーが scala のジェネリックの制限を理解する正しい方法は何ですか? (なぜscalaでこれを行うことができないのですか?例えば、インスタンス化される前にジェネリックがコンパイルされるからですか?)

4

5 に答える 5

6

簡単に言えば、次のようなことができます。

scala> :paste
// Entering paste mode (ctrl-D to finish)

import math.Numeric
import math.Numeric.Implicits._

case class Point2[A: Numeric](x: A, y: A) {
  def + (other: Point2[A]): Point2[A] =
    Point2(this.x + other.x, this.y + other.y)

  def sumComponents: A = x + y
}

// Exiting paste mode, now interpreting.

import math.Numeric
import math.Numeric.Implicits._
defined class Point2

scala> val p1 = Point2(1, 2)
p1: Point2[Int] = Point2(1,2)

scala> val p2 = Point2(3, 4)
p2: Point2[Int] = Point2(3,4)

scala> p1 + p2
res2: Point2[Int] = Point2(4,6)

scala> val p3 = Point2(1.2, 3.4)
p3: Point2[Double] = Point2(1.2,3.4)

scala> val p4 = Point2(1.6, 6.4)
p4: Point2[Double] = Point2(1.6,6.4)

scala> p3 + p4
res3: Point2[Double] = Point2(2.8,9.8)

scala>
于 2013-08-21T01:15:09.550 に答える
2

これには、型クラス (私は を呼び出していAdditionます) と暗黙の変換 (私は と呼ばれる暗黙のクラスを介して定義していOpます) が必要です。実際には、Numericこの特定の状況でタイプを使用しますが、説明のために、独自の定義方法を以下に示します。

trait Addition[T] {

  def add(a: T, b: T): T

  implicit class Op(a: T) { 
    def +(b: T) = add(a, b)
  }
}

implicit object IntAddition extends Addition[Int] {
  def add(a: Int, b: Int) = a + b
}

implicit object DoubleAddition extends Addition[Double] {
  def add(a: Double, b: Double) = a + b
}

case class Point2[T](x: T, y: T)(implicit addition: Addition[T]) {

  import addition.Op

  def +(p: Point2[T]): Point2[T] = Point2(x + p.x, y + p.y)
  def sumComponents(): T = x + y
}
于 2013-08-21T01:17:02.530 に答える
2

Numericとして利用できますimplicit

import scala.math.Numeric;
case class Point2[T](x: T, y: T)(implicit num: Numeric[T])

Numeric APIを見て、必要なことを行います。

于 2013-08-21T01:04:04.147 に答える
2

ライブラリtemplate.scalaを作成しました。ライブラリを使用して、複雑なimplicits を回避して、C++ 風味のテンプレートを作成できます。

import com.thoughtworks.template
case class Point2[T](x:T, y:T) {
   @template def +(rhs: Point2[_]) = Point2(x + rhs.x, y + rhs.y)
   @template def sumComponents() = x + y
}

println(Point2(1, 3).sumComponents()) // Output: 4
println(Point2(1, 3) + Point2(100, 200)) // Output: Point2(101,203)

Point2コンポーネント タイプが異なる2 つの を追加することもできることに注意してください。

println(Point2(1.5, 0.3) + Point2(100, 200)) // Output: Point2(101.5,200.3)

ネストされていてもPoint2

// Output: Point2(Point2(10.1,20.2),Point2(101.0,202.0))
println(Point2(Point2(0.1, 0.2), Point2(1.0, 2.0)) + Point2(Point2(10, 20), Point2(100, 200)))

@template関数は呼び出しサイトでインライン化されるコード テンプレートであるため、機能します。

于 2017-03-09T05:10:31.850 に答える