I changed type to Monoid[Fuel[F]]
, specified return type of implicit def
and Fuel#+
and it works:
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. But here is more interesting example: http://ideone.com/QKuCad. As you see, to make it work correctly I had to define the implicit value of a specified type (line 44). Is there any way to make this procedure more automated? (I mean, is there any way to make fuelMonoid
acceptable as an implicit of any concrete FuelType
subtype?)
Upd2. Yes, in fact there is: http://ideone.com/UEaFRj.