问题很简单,我有一个对象,它使用两个参数进行二进制操作。我想只添加具有相同类型的燃料,如下所示:
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
}
答案 0 :(得分:0)
我将类型更改为Monoid[Fuel[F]]
,指定的返回类型为implicit def
和Fuel#+
并且有效:
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)))
}
}
Upd1。但这里有一个更有趣的例子:http://ideone.com/QKuCad。如您所见,为了使其正常工作,我必须定义指定类型的隐式值(第44行)。有没有办法让这个程序更加自动化? (我的意思是,有没有办法让fuelMonoid
作为隐含的任何具体FuelType
子类型被接受?)
UPD2。是的,实际上有:http://ideone.com/UEaFRj。