2013-12-11 29 views
1

我爲了科學編程學習scala。我正在嘗試使用spire編寫一些簡單的通用代碼。我有下面的例子工作:獲取exp在spire中工作

import spire.algebra._ 
import spire.math._ 
import spire.implicits._ 
object TestSqrt { 
    def testSqrt[T: Numeric](x: T) = { 
     sqrt(x) 
    } 

    def main(args: Array[String]){ 
     val x_d: Double = 4.0 
     println(testSqrt(x_d)) 

     val x_i: Int = 4 
     println(testSqrt(x_i)) 
    } 
} 

這將打印出2.0和2,如預期。問題是我無法獲得與exp函數一樣的工作。下面的代碼無法編譯:

import spire.algebra._ 
import spire.math._ 
import spire.implicits._ 
object TestExp { 
    def testExp[T: Numeric](x: T) = { 
     exp(x) 
    } 

    def main(args: Array[String]){ 
     val x_d: Double = 4.0 
     println(testExp(x_d)) 

     val x_i: Int = 4 
     println(testExp(x_i)) 
    } 
} 

編譯器說:

... could not find implicit value for parameter t: spire.algebra.Trig[T] 
[error]   exp(x) 
[error]   ^ 
[error] one error found 
[error] (compile:compile) Compilation failed 

上午我做錯了什麼,爲試驗尚不支持,或者這是一個錯誤?任何人都可以提供一個使用exp從spire的通用數字類型的工作示例?

UPDATE:

我可以使用,而不是數字觸發,這樣做EXP工作:

import spire.algebra._ 
import spire.math._ 
import spire.implicits._ 
object TestExp { 
    def testExp[T: Trig](x: T) = { 
     exp(x) 
    } 

    def main(args: Array[String]){ 
     val x_d: Double = 1.0 
     println(testExp(x_d)) 

     val x_f: Float = 1.0f 
     println(testExp(x_f)) 
     // val x_i: Int = 4 
     // println(testExp(x_i)) 
    } 
} 

但是,它不與詮釋工作,只有浮點類型。此外,如果我使用Trig,那麼我不能使用sqrt。下面的代碼無法編譯:

}

import spire.algebra._ 
import spire.math._ 
import spire.implicits._ 
object TestSqrt { 
    def testSqrt[T: Trig](x: T) = { 
     sqrt(x) 
    } 

    def main(args: Array[String]){ 
     val x_d: Double = 4.0 
     println(testSqrt(x_d)) 

     val x_i: Int = 4 
     println(testSqrt(x_i)) 
    } 
} 

,並給出了錯誤:

... could not find implicit value for evidence parameter of type spire.algebra.Trig[Int] 
[error]   println(testSqrt(x_i)) 
[error]      ^
[error] two errors found 
[error] (compile:compile) Compilation failed 

如果我想都exp和開方我應該怎麼做,是有辦法使exp與Integral類型一起工作?

回答

3

類型類定義爲具有相同類型的操作數和操作結果。也就是說,當您對A類型的值運行sqrt時,結果也將爲A

現在你可能會爭辯sqrt整數得到整數對於一些特定的輸入值,如你在例子中使用的4。另一方面,sqrt(5)應該返回什麼?看起來它會返回比實際平方根更小的最大整數:

def testSqrt[T: Numeric](x: T): T = sqrt(x) 

scala> testSqrt(5) 
res0: Int = 2 

這並不是你想要的。有趣的是,當你直接調用sqrt功能,它會返回一個Double

scala> sqrt(5) 
res1: Double = 2.23606797749979 

的原因是,當您導入spire.math._你會得到一個重載sqrt功能:

final def sqrt(x: Double): Double = Math.sqrt(x) 
final def sqrt[A](a: A)(implicit ev: NRoot[A]): A = ev.sqrt(a) 

這種「解決」了通過給予第一個變體優先級來解決問題(因爲它不需要隱式參數)。在你的例子中發生的是你使用了一個通用簽名,因此第二個版本的sqrt將被調用。 NRoot參數是間接提供的,因爲你說你有一個Numeric

所以你將不得不決定你要做什麼 - 你想在計算平方根時回退到Double,還是用這個非常規的想法來截斷結果呢?


現在要求冪。在math,有再次重載版本exp,其中:

final def exp(n: Double): Double = Math.exp(n) 
final def exp[A](a: A)(implicit t: Trig[A]): A = t.exp(a) 

sqrt不同的是,你不會得到一個Trig[Int]在任何情況下。沒有什麼有意義的方法。

讓我們只定義可以基於該類型類調用sqrtexp功能:

def sqrtAndExp[T: NRoot: Trig](x: T): (T, T) = (sqrt(x), exp(x)) 

你看你可以使用在函數聲明的約束多個方面。該語法等同於

def sqrtAndExp[T](x: T)(implicit nroot: NRoot[T], trig: Trig[T]: (T, T) = 
    (sqrt(x), exp(x)) 

雙打,此功能(因爲你已經輸入spire.implicits._):

scala> sqrtAndExp(5.0) 
res2: (Double, Double) = (2.23606797749979,148.4131591025766) 

但不是整數:

scala> sqrtAndExp(5) 
<console>:18: error: could not find implicit value for evidence parameter of type 
        spire.algebra.Trig[Int] 
       sqrtAndExp(5) 
         ^

整數總是可以使用然而,雙打是必需的。所以你可以讓它工作:

scala> sqrtAndExp[Double](5) 
res3: (Double, Double) = (2.23606797749979,148.4131591025766) 
+0

非常明確,並解決我的問題。我不知道你可以使用多個上下文邊界。 – jcrudy

+0

顯然你也可以添加一個重載函數'def sqrtAndExp(x:Double):(Double,Double)',如果你想能夠用整數文字來調用它的話。 –