scala中集合的隐式Impl方法

scala中集合的隐式Impl方法,scala,implicit,scala-breeze,Scala,Implicit,Scala Breeze,我在SortedMap[Int,Double]上有一个类型别名,我希望有一个隐式的别名,允许我将SortedMap传递给breeze中的一些内置函数,特别是breeze.stats.函数variance和stddev 下面是一个没有隐含含义的工作示例: package com.soquestion import breeze.linalg._ import breeze.stats._ import scala.collection.SortedMap import scala.languag

我在
SortedMap[Int,Double]
上有一个类型别名,我希望有一个隐式的别名,允许我将
SortedMap
传递给breeze中的一些内置函数,特别是
breeze.stats.
函数
variance
stddev

下面是一个没有隐含含义的工作示例:

package com.soquestion

import breeze.linalg._
import breeze.stats._
import scala.collection.SortedMap
import scala.language.implicitConversions

object proof {
  type Series = SortedMap[Int, Double]

  def example: Double = {
    val s: Series = SortedMap(1 -> 9.0, 2 -> 2.0, 3 -> 5.0, 4 -> 4.0, 5 -> 12.0, 6 -> 7.0, 7 -> 8.0, 8 -> 11.0, 9 -> 9.0, 10 -> 3.0, 11 -> 7.0, 12 -> 4.0, 13 -> 12.0, 14 -> 5.0, 15 -> 4.0, 16 -> 10.0, 17 -> 9.0, 18 -> 6.0, 19 -> 9.0, 20 -> 4.0)

    stddev(s.values)
  }
}
在sbt控制台中运行

scala> com.soquestion.proof.example
res0: Double = 3.0607876523260447
我希望不必指定
.values
,只需调用
stddev
方差即可

这是我试过的

package com.soquestion

import breeze.linalg._
import breeze.stats._
import scala.collection.SortedMap
import scala.language.implicitConversions

object proof {
    // Implicitly convert the SortedMap, or any map, to a DenseVector[Double]
  implicit def series2DenseVector(s: Traversable[(Int, Double)]): DenseVector[Double] = {
    DenseVector(s.map(_._2).toArray)
  }
  type Series = SortedMap[Int, Double]

  def example: Double = {
    val s: Series = SortedMap(1 -> 9.0, 2 -> 2.0, 3 -> 5.0, 4 -> 4.0, 5 -> 12.0, 6 -> 7.0, 7 -> 8.0, 8 -> 11.0, 9 -> 9.0, 10 -> 3.0, 11 -> 7.0, 12 -> 4.0, 13 -> 12.0, 14 -> 5.0, 15 -> 4.0, 16 -> 10.0, 17 -> 9.0, 18 -> 6.0, 19 -> 9.0, 20 -> 4.0)

    stddev(s) // <--- compiler error here
  }
}
浏览breeze文档时,我没有找到一个好的例子来说明我需要提供什么。理想情况下,我希望创建一个隐式,允许我调用
stdev
variance
,而无需多个隐式

我确实看到了这个问题,但我不知道它将如何应用到这个场景中

基于下面@dlwh答案的完整格式答案,以防将来有人需要它

package com.soquestion

import breeze.linalg.support._
import breeze.linalg.support.CanTraverseValues._
import breeze.stats._
import scala.annotation.tailrec
import scala.collection.SortedMap
import scala.language.implicitConversions

object proof {
  type Series = SortedMap[Int, Double]

  def example: Double = {
    // ideally this implicit would go in a scope higher up so it could be
    // brought in wherever it's needed, but this works for a sample
    implicit object SeriesIter extends CanTraverseValues[Series, Double] {
      def isTraversableAgain(from: Series) = true
      def traverse(from: Series, fn: ValuesVisitor[Double]): Unit = {
        @tailrec def traverser(idx: Int, t: Array[Double]): Unit = {
          if (idx == 1) fn.visit(t.head)
          else {
            fn.visit(t.head)
            traverser(idx - 1, t.tail)
          }
        }
        val v: Array[Double] = from.values.toArray
        fn.zeros(0, 0d)
        traverser(v.size, v)
      }
    }

    val s: Series = SortedMap(1 -> 9.0, 2 -> 2.0, 3 -> 5.0, 4 -> 4.0, 5 -> 12.0, 6 -> 7.0, 7 -> 8.0, 8 -> 11.0, 9 -> 9.0, 10 -> 3.0, 11 -> 7.0, 12 -> 4.0, 13 -> 12.0, 14 -> 5.0, 15 -> 4.0, 16 -> 10.0, 17 -> 9.0, 18 -> 6.0, 19 -> 9.0, 20 -> 4.0)
    stddev(s)
  }
}

文档可以做得更好,我真希望我能让错误消息更有帮助

如果你看一下,你会发现它需要一个
variance.Impl
的实现,它需要一个
meansandvariance.Impl
,它可以为任何具有
CanTraverseValues[T,Double]
隐式的类型提供。默认情况下,对于集合有一个隐式的
CanTraverseValues
,但仅在包含的类型上,而不是scala的
Map
类型的值上。 实现CanTraverseValues和CanMapValues将启用大多数breeze UFUNC


Scala通常不会隐式地“链接”,这就是为什么您的
证明
示例不起作用的原因。

谢谢!我最后添加了以下内容,它很好地解决了隐式对象mapLikeIter扩展CanTraverseValues[Series,Double]{def-isTraversableAgain(from:Series)=true-def-traverse(from:Series,fn:ValuesVisitor[Double]):Unit={@tailrec def-traverser(idx:Int,t:Array[Double]):Unit={if(idx==1)fn.visit(t.head)else{fn.visit(t.head)traverser(idx-1,t.tail)}val v:Array[Double]=from.values.toArray fn.zeros(0,0d)traverser(v.size,v)}为更简单的实现提出了一个更改(实际上没有仔细检查,但我认为它是正确的)
package com.soquestion

import breeze.linalg.support._
import breeze.linalg.support.CanTraverseValues._
import breeze.stats._
import scala.annotation.tailrec
import scala.collection.SortedMap
import scala.language.implicitConversions

object proof {
  type Series = SortedMap[Int, Double]

  def example: Double = {
    // ideally this implicit would go in a scope higher up so it could be
    // brought in wherever it's needed, but this works for a sample
    implicit object SeriesIter extends CanTraverseValues[Series, Double] {
      def isTraversableAgain(from: Series) = true
      def traverse(from: Series, fn: ValuesVisitor[Double]): Unit = {
        @tailrec def traverser(idx: Int, t: Array[Double]): Unit = {
          if (idx == 1) fn.visit(t.head)
          else {
            fn.visit(t.head)
            traverser(idx - 1, t.tail)
          }
        }
        val v: Array[Double] = from.values.toArray
        fn.zeros(0, 0d)
        traverser(v.size, v)
      }
    }

    val s: Series = SortedMap(1 -> 9.0, 2 -> 2.0, 3 -> 5.0, 4 -> 4.0, 5 -> 12.0, 6 -> 7.0, 7 -> 8.0, 8 -> 11.0, 9 -> 9.0, 10 -> 3.0, 11 -> 7.0, 12 -> 4.0, 13 -> 12.0, 14 -> 5.0, 15 -> 4.0, 16 -> 10.0, 17 -> 9.0, 18 -> 6.0, 19 -> 9.0, 20 -> 4.0)
    stddev(s)
  }
}