2016-09-06 6 views
0

スカラ型のシステムで遊んでいて、もう一度私はそれと戦っているのです。私はいくつかのシンプルなグラフィックスアプリケーション用のVectorライブラリを作成しました。scala higher種類とscalatic equalality

今、私はscalacheckとscalatestを使ってVectorプロパティをテストしたいと思っています。私が直面している問題は、倍精度または浮動小数点数を使用するときにベクトルの等価性をチェックすることは、思ったほど簡単ではないということです。今私は、テストフレームワークで最も慣用的な方法は、私のベクトルクラスのnew Equalityを作成することであることを考え出しました。しかし、背中のステップと私のベクトルdefenitionsまた、ここで適用を解除する図示していない

abstract class Vec[T, V[T] <: Vec[T, V]](val elems: T*)(implicit num: VecIntegral[T], factory: VecFactory[V]) 
class Vec2[T](x: T, y: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec2](x,y) 
Vec3[T](x: T, y: T, z: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec3](x,y, z) 

を見てみると、パターンマッチングなどを可能にVecとオブジェクトのために定義されて適用できます。

は、だから今テストを書くための私の最初の試みは、この

abstract class VecSuite[T: Arbitrary, V[T] <: Vec[T, V]](implicit genVec: Arbitrary[V[T]], num: VecIntegral[T]) 
    extends PropSpec with PropertyChecks { 
    import num._ 

    property("associative add") { 
    forAll { (a: V[T], b: V[T]) => 
     assert((a + b).===(b + a)) 
    } 
    } 

    property("scalar distributed") { 
    forAll { (a: V[T], b: V[T], s: T) => 
     assert((a + b) * s === a * s + b * s) 
    } 
    } 
... 
} 
class Vec2IntSuite extends VecSuite[Int, Vec2] 
class Vec2FloatSuite extends VecSuite[Float, Vec2] 
class Vec2DoubleSuite extends VecSuite[Double, Vec2] 
class Vec2LongSuite extends VecSuite[Long, Vec2] 

ようになります。ここで再び、私はショーをいけないが、私はVec2[T]Vec3[T]のクラスの実装暗黙の工場があります。

これは本当にうまくいきます。 FloatDoubleの場合、丸め誤差が発生し、等価チェックが爆発するという点を除いて、一般的なテストを書いて、サポートされているすべての異なるVector実装に適用できます。

だから今、私は私だけDoubleFloatのための2つの暗黙の値の試行を必要とするようにVec2Vec2の間で、それは一般的にしようとしてEqualityクラスで遊んで開始します。

implicit val doubleEq = new Equality[ V[Double] forSome{ type V[Double] <: Vec[Double, V] }] { 
    override def areEqual(a: V[Double] forSome {type V[Double] <: Vec[Double, V]}, b: Any): Boolean = (a,b) match { 
    case (lhs: Vec[Double, _], rhs: Vec[Double, _]) => lhs.elems.zip(rhs.elems).forall {case (e1, e2) => e1 === e2 +- 0.01d } 
    case _ => false 
    } 
} 

しかし、これは座っていません。コンパイラでうまくいけば、それはjava.lang.StackOverflowExceptionで爆発する。

は、それがVec2Vec3であれば、それは暗黙のうちに私のテストケースで使用されるようにEqualityの種類を書くのいずれかの方法がある限り、それはタイプDoubleであるよう関わらずありますか?

答えて

0

申し訳ありませんが、私は実際にこれを解決しました!

class VecDoubleEquality[V[Double] <: Vec[Double, V]] extends Equality[V[Double]] { 
    override def areEqual(a: V[Double], b: Any): Boolean = (a,b) match { 
    case (lhs: Vec[Double, V], rhs: Vec[Double, V]) => lhs.elems.zip(rhs.elems).forall {case (e1, e2) => e1 === e2 +- 0.1d } 
    case _ => false 
    } 
} 
implicit def doubleEq[V[Double] <: Vec[Double, V]] = new VecDoubleEquality[V] 

これは正しくforSome実存ビットを気にしなくても、私に再帰的なタイプと右型シグネチャを与えるだろう。