2015-11-20 1 views
2

У меня есть псевдоним типа на SortedMap[Int, Double], и я хотел бы иметь неявное, что позволяет мне передавать мои SortedMap некоторым встроенным функциям на ветру, в частности функции breeze.stats._variance и stddev.неявный метод Impl для коллекций в scala breeze

Вот рабочий пример без implicits:

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 console

scala> com.soquestion.proof.example 
res0: Double = 3.0607876523260447 

То, что я хотел бы, чтобы не указывать .values и просто позвонить stddev(s) и variance(s).

Вот что я пытался

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 
    } 
} 

, но я получаю ошибку компиляции из

could not find implicit value for parameter impl: breeze.stats.stddev.Impl[com.soquestion.proof.Series,VR] 

, проходящую через документацию ветер, я не смог найти хороший пример того, что неявного мне нужно предоставлять. В идеале я хотел бы сделать одно неявное, что позволило бы мне звонить как stdev, так и variance без нескольких имплицитов.

Я видел вопрос Scala Breeze DenseVector Implicit failure, но я не вижу, как это применимо к этому сценарию.

Полный отформатированный ответ, основанный на ответ @ 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) 
    } 
} 
+0

предложил изменение для более простой реализации (на самом деле не проверял его дважды, но я думаю, что это правильно) – dlwh

ответ

2

Документах можно было бы гораздо лучше для этого, и я хотел бы сделать сообщения об ошибках более полезно.

Если посмотреть на stddev's source вы увидите, что он требует реализации variance.Impl, что требует meanAndVariance.Impl, который может быть предоставлен для любого типа, который имеет CanTraverseValues[T, Double] неявное. По умолчанию для коллекций существует неявный CanTraverseValues, но только для указанного типа, а не для значений типа scala Map. Реализация CanTraverseValues ​​и CanMapValues ​​позволит использовать большинство UFuncs.

Scala обычно не будет «цепляться», поэтому ваш пример proof не работает.

+1

Спасибо! Я закончил тем, что добавил следующее, и он решил это красиво неявный объект 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. голова) транспортер (IDX - 1, t.tail) }} вал v: Массив [Двойной] = from.values.toArray fn.zeros (0, 0d) транспортер (ст.размер, v) } } –

Смежные вопросы