5

type のすべてのサブタイプで機能する汎用の暗黙的なコンバーターを定義したいと思いますT。例えば:

abstract class Price[A] {
  def price(a: Any): Int
}

trait Car
case class Prius(year: Int) extends Car
trait Food
case class FriedChicken() extends Food

object Def {
  implicit def carToPrice[A <: Car](car: A): Price[A] = new Price[A] {
    def price(car: Any) = 100
  }

  implicit def foodToPrice[A <: Food](food: A): Price[A] = new Price[A] {
    def price(food: Any) = 5
  }

  // implicit object PriusPrices extends Price[Prius] {
  //   def price(car: Any) = 100
  // }
  // 
  // implicit object FriedChickenPrices extends Price[FriedChicken] {
  //   def price(food: Any) = 5
  // }
}

import Def._  

def add [A, B >: A](stuff: A, list: List[(B, Price[_])])(implicit p: Price[A]) = (stuff, p) :: list
val stuff = add(Prius(2000), add(FriedChicken(), Nil))
stuff map { x => x._2.price(x._1) }

上記のコードはエラーをスローします。

error: could not find implicit value for parameter p: Price[FriedChicken]
       val stuff = add(Prius(2000), add(FriedChicken(), Nil))
                                       ^

私は何を間違っていますか?

更新

@extempore指摘したように、間違っているのは、暗黙の変換 (ビュー境界) とコンテキスト境界 (両方とも暗黙のパラメーターを使用する) を混同していることです。私の一般的な暗黙のコンバーターには何の問題もありません。問題はadd、ビューの代わりにコンテキスト境界を使用していることです。したがって、次のように修正できます。

def add [A, B >: A](stuff: A, list: List[(B, Price[_])])(implicit view: A => Price[A]) = (stuff, view(stuff)) :: list

@extempore が彼のコードで示している興味深いことは、Price[A]反変である場合、一般的なコンバーターは実際には必要ないということです。基本的に、私はPrice[Car]に代わって仕事をすることができますPrice[Prius]。これは私が望んでいたことの一種です。したがって、代替のコンテキスト バインド バージョンは次のとおりです。

abstract class Price[-A] {
  def price(a: Any): Int
}

implicit object CarPrice extends Price[Car] {
  def price(a: Any) = 100
}

implicit object FoodPrice extends Price[Food] {
  def price(a: Any) = 1
}

関連

4

3 に答える 3

8

あなたが本当に何を望んでいるのかはあまり明確ではありません。あなたは確かに暗黙の変換と暗黙のパラメータを混同しています。それを整理しようとするのではなく、私はいくつかのコードを書きました。

object Test {
  type Price = Int
  abstract class Pricable[-A] {
    def price(a: A): Price
  }

  trait Car
  case class Prius(year: Int) extends Car
  trait Food
  case class FriedChicken() extends Food

  implicit val CarPricingGun = new Pricable[Car] { 
    def price(a: Car): Price = 100
  }
  implicit val FoodPricingGun = new Pricable[Food] { 
    def price(a: Food): Price = 1
  }
  implicit def priceableItemToPrice[A: Pricable](x: A) =
    implicitly[Pricable[A]] price x

  def main(args: Array[String]): Unit = {
    val x1 = Prius(2000)
    val x2 = FriedChicken()

    println("Price of " + x1 + " is " + (x1: Price))
    println("Price of " + x2 + " is " + (x2: Price))
  }
}
// Output is:
//
// Price of Prius(2000) is 100
// Price of FriedChicken() is 1
// 
于 2010-10-02T04:16:59.500 に答える
2

問題は、暗黙的carToPriceおよびfoodToPrice暗黙的なメソッドをaCarFoodvaluesからPricesに定義したにもかかわらず、変換が必要な場所にCarandの値がないことです。Foodこれらの暗黙的なメソッドでは実際には引数を使用しないので、本当に必要だと思うのは、次のような暗黙の値です。

implicit def carToPrice[A <: Car]/*(car: A)*/: Price[A] = new Price[A] {
  def price(car: Any) = 100
}

implicit def foodToPrice[A <: Food]/*(food: A)*/: Price[A] = new Price[A] {
  def price(food: Any) = 5
}
于 2010-10-01T23:28:20.257 に答える
0

@extempore指摘したように、問題は、暗黙の変換(ビューの境界)とコンテキストの境界(両方とも暗黙のパラメーターを使用)を混同していることです。私の一般的な暗黙のコンバーターには何も問題はありません。問題はadd、ビューの代わりにコンテキスト境界を使用していることです。したがって、次のように修正できます。

def add [A, B >: A](stuff: A, list: List[(B, Price[_])])(implicit view: A => Price[A]) = (stuff, view(stuff)) :: list
于 2010-10-02T05:39:31.280 に答える