2012-02-12 6 views
7

私はScalaにとってかなり新しいです。いくつかの演算(+、 - 、*)の下で閉ざされたいくつかの数学的オブジェクト(Complex、Polynomialなど)をジェネリックで使用できるように記述したいし、暗黙のキャストを使うこともできます。数字を実装する

私は最初のビットを解決したようです。複雑な

test(Real(5), Complex(2, 1)) 

リターン(7、1)となるよう

trait GroupUnderAddition[T] { 
    def + (t : T) : T 
} 

case class Real(d : Double) extends GroupUnderAddition[Real] { 
    def + (r : Real) = Real(d + r.d) 
} 

case class Complex(re : Double, im : Double) extends GroupUnderAddition[Complex] { 
    def + (c : Complex) = Complex(re + c.re, im + c.im) 
} 

object Test { 
    implicit def real_to_complex(r : Real) = Complex(r.d, 0) 

    def test[G <: GroupUnderAddition[G]](a : G, b : G) = a + b 

    def main(args : Array[String]) { 
    println(test(Real(5), Real(2))) 
    } 
} 

、どのように私は)(テストを書くことができますか?

答えて

2

主な考え方は、すべてのGroupUnderAdditionが互換性がないということです。複雑な代数で作業したいと思うように、GoupUnderAdditionを含むスーパークラスを作成することをお勧めします。それをケースクラスを作成することは推奨されませんが(あなたが持っている場合は警告が表示case class拡張case class

trait GroupUnderAddition[T] { 
    def + (t : T) : T 
} 

class ComplexAlgebra(_re:Double, _im:Double) extends(GroupUnderAddition[ComplexAlgebra]) { 
    val re = _re 
    val im = _im  
    def + (c : ComplexAlgebra) = new ComplexAlgebra(re + c.re, im + c.im) 
} 

case class Real(d : Double) extends ComplexAlgebra(d, 0) 

case class Complex(real : Double, imaginary : Double) extends ComplexAlgebra(real,imaginary) 

object Test { 

    def test(a : ComplexAlgebra, b : ComplexAlgebra) = a + b 

    def main(args : Array[String]) { 
    println(test(Real(5), Real(2))) 
    } 
} 
+0

確かに私はこれを行うことができましたが、ジェネリック薬を服用したいと思います。自分のやり方で、2つの多項式でテストを呼びたい場合は、すべてを書き直す必要があります。 –

+0

はい、2つの問題があります。まず、 '+'メソッドを実装する汎用の 'GroupUnderAddition'を作成したいということです。一方、 'Real'と' Complex'の2種類の数字を実装した特定の 'GroupUnderAddition'を使いたいとします。だからあなたは別のトリックをしなければなりません、これがあなたが '暗黙のdef'について考えた理由ですが、あなたのケースで私はこれで解決策を見つけられませんでした。 –

1

問題は、あなたがにメソッド定義を指定しない限りimplicit defは、引数の変換のために考慮されていないということですそうする。あなただけ複雑に定義されているReal(5).foofooのようなものを持っている場合

したがって、implicit defはそのために動作します。

def foo(c : Complex) = ...のような方法がある場合は、代わりにfoo(Real(5))で呼び出すことはできません。

暗黙の変換を適用する場合は、引数を変換できるようにメソッドを指定する必要があります。あなたはこのようにそれを行うことができます上記foo方法について:

def foo[T](c : T)(implicit ct : T => Complex) = ...` 

そして、foo(Real(5))を呼び出すために、変換が使用されます有効です。あなたの特定の問題に適応し

、あなたがこのような試験方法書くことができます:TからGへの暗黙の型変換を考慮しなければならないことを、指定することで

def test[G <: GroupUnderAddition[G],T](a : T, b : G)(implicit ag: T => G) = a + b 

を、あなたが今受け入れるtest方法を許可しますtest(Real(5), Complex(2,1))

しかし、それ以外の方法ではまだ動作しません。したがって、第2引数の暗黙の変換がないので、まだtest(Complex(2,1), Real(5))で呼び出すことはできません。上記のように、このメソッドを呼び出すときに

def test[G <: GroupUnderAddition[G],T1, T2](a : T1, b : T2)(implicit ag: T1 => G, bg: T2 => G) = a + b 

残念ながら、コンパイラは何とかGためAnyを導出:両方の変換を考慮して

簡単な方法は、このようにそれを書くことになります。私は今、この問題を解決する方法を知らないし、他の誰かがパズルのこの最後の部分を記入してくれることを期待してこの答えを投稿しました。

println(test[Complex,Real,Complex](Real(5), Complex(2, 1))) 
println(test[Complex,Complex,Real](Complex(2,1), Real(5))) 
1

ここでの本当の問題は、あなたがそのtest(Real(5), Complex(2, 1))(間違った)仮定を作っているということである:フルタイプを指定するときは、少なくとも、いずれかの方法でメソッドを呼び出すことができます上記の最終的な定義を考えると

あなたが書いたことを考えれば、どんな意味でも明確に定義されています。次のことを考えてみましょう:

case class Word(s : String) extends GroupUnderAddition[Word] { 
    def +(w : Word) = Word(s + w.s) 
} 

これは完全に「GroupUnderAddition」のあなたの定義を満たすが、それはレアル(2)に言葉(「こんにちは」)を追加しようとするのは意味がありません。結果は何ですか?

エンコードしようとしているのは、より大きなドメイン内の特定の加算演算子です.Cの多項式のドメインのように見え、この演算子の特定のサブグループは加算演算子の下で閉じられています。 ChrisJamesCのアプローチは、幸せに多項式の環に拡張することができ、あなたが望むものを捕捉することができます。

+0

test(Real(5)、Complex(2,1))は、暗黙のReal => Complex関数があることを考慮して、よく定義されています。私はGroupUnderAdditionの2人の子供のためにこの仕事をするつもりはありません。 –

関連する問題