1

问题很简单,我有一个对象用两个参数进行二元运算。我只想添加具有相同类型的燃料,如下所示:

object Fuels {

  case class Fuel[F <: FuelType](amount: Double, fuelType: F = Petrol) {
    def +(that : Fuel[F]) = {
      copy(amount = this.amount + that.amount)
    }
  }

  def add[F <: FuelType](x: Fuel[F], y: Fuel[F]): Fuel[F] = x + y

  sealed trait FuelType {
    val name : String
  }
  case object Petrol extends FuelType{
    override val name = "Petrol"
  }
  case object Diesel extends FuelType{
    override val name = "Diesel"
  }
  case object Hydrogen extends FuelType{
    override val name = "Hydrogen"
  }

 implicit def fuelMonoid[F <:FuelType](implicit fuelType: F) = new Monoid[Fuel]{
     override def zero: Fuel[F] = Fuel(0, fuelType)
     override def append(m1: Fuel[F], m2: Fuel[F]) : Fuel[F] = m1 + m2
   }

}

用它:

> Fuel(10, Petrol) + Fuel(20, Petrol)
> add(Fuel(10, Petrol), Fuel(10, Petrol))

编译错误:

Expression of Type Fuels.Fuel[Nothing] does not conform to Fuels.Fuel[F]

主要问题是 add 和fuelMonoid 都无法识别我们正在处理相同类型的项目。编译器无法解析类型约束,并推断 Nothing。

为了完成,这里是 Monoid,没什么特别的:

trait Monoid[A] {
  def zero: A
  def append(a1: A, a2: A): A
}
4

1 回答 1

0

我将 type 更改为Monoid[Fuel[F]],指定的返回类型implicit defandFuel#+并且它可以工作:

object Fuels {

  trait Monoid[F] {
    def zero: F
    def append(f1: F, f2: F): F
  }

  object Monoid {
    def fold[F](as: Seq[F], m: Monoid[F]): F = as.foldLeft(m.zero)(m.append)
  }

  case class Fuel[F <: FuelType](amount: Double, fuelType: F = Petrol) {
    def +(that : Fuel[F]): Fuel[F] = {
      copy(amount = this.amount + that.amount)
    }
  }

  def add[F <: FuelType](x: Fuel[F], y: Fuel[F]): Fuel[F] = x + y

  sealed trait FuelType {
    val name : String
  }
  case object Petrol extends FuelType{
    override val name = "Petrol"
  }
  case object Diesel extends FuelType{
    override val name = "Diesel"
  }
  case object Hydrogen extends FuelType{
    override val name = "Hydrogen"
  }

  implicit def fuelMonoid[F <:FuelType](implicit fuelType: F): Monoid[Fuel[F]] = new Monoid[Fuel[F]] {
    override def zero: Fuel[F] = Fuel(0, fuelType)
    override def append(m1: Fuel[F], m2: Fuel[F]): Fuel[F] = m1 + m2
  }
}

object Main {
  def main (args: Array[String] ) {
    import Fuels._
    println(Fuel(10, Petrol) + Fuel(20, Petrol))
    println(add(Fuel(10, Petrol), Fuel(20, Petrol)))
    println(Monoid.fold(Seq(Fuel(10, Petrol), Fuel(20, Petrol), Fuel(30, Petrol)), fuelMonoid(Petrol)))
  }
}

http://ideone.com/kRockk

更新1。但这里有一个更有趣的例子:http: //ideone.com/QKuCad。如您所见,为了使其正常工作,我必须定义指定类型的隐式值(第 44 行)。有什么方法可以使这个过程更加自动化?(我的意思是,有什么方法可以使fuelMonoid任何具体子类型的隐含接受FuelType?)

更新2。是的,事实上有:http: //ideone.com/UEaFRj

于 2014-05-08T14:32:10.407 回答