[scala] What is the equivalent of this program using type parameters?

View: New views
7 Messages — Rating Filter:   Alert me  

[scala] What is the equivalent of this program using type parameters?

by Mushtaq Ahmed :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Problem statement: 
- Allow addition of KG + Gram, Meter + Kilometer but prevent addition of Meter and Miles
- Allow conversion from Meter to Miles, KG to pounds but prevent conversion from Miles to Grams
- Allow multiplication of any two units (return type Double)

I came up with the following program using abstract type members, but still struggling to find solution using type parameters/generics. Will appreciate any help/guidance. Thanks.

trait AbstractMeasure {
  type Quantity <: AbstractQuantity
  trait AbstractQuantity { this: Quantity =>
    
   type Unit <: AbstractUnit
trait AbstractUnit { 

 val amount: Double
 implicit val implicitThis = this

def +(that: Unit) = make(amount + that.to[this.type].amount)
def *(that:  AbstractMeasure#AbstractQuantity#AbstractUnit) = amount * that.amount
def *(that: Double) = make(amount * that)
def to[T<: Quantity#AbstractUnit](implicit m: Manifest[T]) = {
val mappedUnit = convert(make(1)).find(_.getClass == m.erasure).get
mappedUnit * amount
}
}
}
}

object Singleton {
  
  type U = AbstractMeasure#AbstractQuantity#AbstractUnit
  
  def convert: Map[U,List[U]] = Map(
   Meter(1) -> List(Meter(1), KM(0.001) , Mile(0.00062), Yard(1.093)),
   KM(1) -> List(Meter(1000), KM(1) , Mile(0.62), Yard(1093)),
   Mile(1) -> List(Meter(1609), KM(1.069) , Mile(1), Yard(1760)),
   ....
  )
  
  def make(x: Double)(implicit o: U): U = o match {
case Meter(_) => Meter(x)
case KM(_) => KM(x)
case Mile(_) => Mile(x)
...
  }
}

object Length extends AbstractMeasure {

  type Quantity = LengthQuantity
  trait LengthQuantity extends AbstractQuantity
  
  object Metric extends LengthQuantity {
  
    type Unit = LengthUnit
    trait LengthUnit extends AbstractUnit
    
    case class Meter(amount: Double) extends LengthUnit 
    case class KM(amount: Double) extends LengthUnit 
  }

  object English extends LengthQuantity {
    
    type Unit = LengthUnit
    abstract class LengthUnit extends AbstractUnit
    
    case class Mile(amount: Double) extends LengthUnit 
    case class Yard(amount: Double) extends LengthUnit 
  }
}

object Weight extends AbstractMeasure {
  
  type Quantity = WeightQuantity
  trait WeightQuantity extends AbstractQuantity 
  
  object Metric extends WeightQuantity {
  
    type Unit = WeightUnit
    trait WeightUnit extends AbstractUnit
    
    case class Gram(amount: Double) extends WeightUnit 
    case class KG(amount: Double) extends WeightUnit
  }
  
  object English extends WeightQuantity {
    
    type Unit = WeightUnit
    trait WeightUnit extends AbstractUnit
    
    case class Pound(amount: Double) extends WeightUnit
    case class Ounce(amount: Double) extends WeightUnit
  }
}

import Length.Metric._, Length.English._, Weight.Metric._, Weight.English._

println(KM(4) + Meter(5)) => KM(4.005)
println(KM(5) + Mile(3)) //compile time error
println(KM(5).to[Yard]) => Yard(5465.0)
println(KG(2).to[Mile])  //compile time error
println(Meter(3) * Gram(9)) => 27


Re: [scala] What is the equivalent of this program using type parameters?

by Luc Duponcheel :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Ahmed,

your example
sounds similar to the Mars Climate Orbiter one
which is the stereotypical example to make use
of type members in the first place

why do you want a solution using type parameters?

I'm not sure you'll find one that is more elegant than
one using type members

Luc

On Fri, Oct 16, 2009 at 2:38 PM, Mushtaq Ahmed <mushtaq.a@...> wrote:
Problem statement: 
- Allow addition of KG + Gram, Meter + Kilometer but prevent addition of Meter and Miles
- Allow conversion from Meter to Miles, KG to pounds but prevent conversion from Miles to Grams
- Allow multiplication of any two units (return type Double)

I came up with the following program using abstract type members, but still struggling to find solution using type parameters/generics. Will appreciate any help/guidance. Thanks.

trait AbstractMeasure {
  type Quantity <: AbstractQuantity
  trait AbstractQuantity { this: Quantity =>
    
   type Unit <: AbstractUnit
trait AbstractUnit { 

 val amount: Double
 implicit val implicitThis = this

def +(that: Unit) = make(amount + that.to[this.type].amount)
def *(that:  AbstractMeasure#AbstractQuantity#AbstractUnit) = amount * that.amount
def *(that: Double) = make(amount * that)
def to[T<: Quantity#AbstractUnit](implicit m: Manifest[T]) = {
val mappedUnit = convert(make(1)).find(_.getClass == m.erasure).get
mappedUnit * amount
}
}
}
}

object Singleton {
  
  type U = AbstractMeasure#AbstractQuantity#AbstractUnit
  
  def convert: Map[U,List[U]] = Map(
   Meter(1) -> List(Meter(1), KM(0.001) , Mile(0.00062), Yard(1.093)),
   KM(1) -> List(Meter(1000), KM(1) , Mile(0.62), Yard(1093)),
   Mile(1) -> List(Meter(1609), KM(1.069) , Mile(1), Yard(1760)),
   ....
  )
  
  def make(x: Double)(implicit o: U): U = o match {
case Meter(_) => Meter(x)
case KM(_) => KM(x)
case Mile(_) => Mile(x)
...
  }
}

object Length extends AbstractMeasure {

  type Quantity = LengthQuantity
  trait LengthQuantity extends AbstractQuantity
  
  object Metric extends LengthQuantity {
  
    type Unit = LengthUnit
    trait LengthUnit extends AbstractUnit
    
    case class Meter(amount: Double) extends LengthUnit 
    case class KM(amount: Double) extends LengthUnit 
  }

  object English extends LengthQuantity {
    
    type Unit = LengthUnit
    abstract class LengthUnit extends AbstractUnit
    
    case class Mile(amount: Double) extends LengthUnit 
    case class Yard(amount: Double) extends LengthUnit 
  }
}

object Weight extends AbstractMeasure {
  
  type Quantity = WeightQuantity
  trait WeightQuantity extends AbstractQuantity 
  
  object Metric extends WeightQuantity {
  
    type Unit = WeightUnit
    trait WeightUnit extends AbstractUnit
    
    case class Gram(amount: Double) extends WeightUnit 
    case class KG(amount: Double) extends WeightUnit
  }
  
  object English extends WeightQuantity {
    
    type Unit = WeightUnit
    trait WeightUnit extends AbstractUnit
    
    case class Pound(amount: Double) extends WeightUnit
    case class Ounce(amount: Double) extends WeightUnit
  }
}

import Length.Metric._, Length.English._, Weight.Metric._, Weight.English._

println(KM(4) + Meter(5)) => KM(4.005)
println(KM(5) + Mile(3)) //compile time error
println(KM(5).to[Yard]) => Yard(5465.0)
println(KG(2).to[Mile])  //compile time error
println(Meter(3) * Gram(9)) => 27




--
  __~O
 -\ <,
(*)/ (*)

reality goes far beyond imagination


[scala] Re: What is the equivalent of this program using type parameters?

by Jesper Nordenberg :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Mushtaq Ahmed wrote:

> Problem statement:
> - Allow addition of KG + Gram, Meter + Kilometer but prevent addition of
> Meter and Miles
> - Allow conversion from Meter to Miles, KG to pounds but prevent
> conversion from Miles to Grams
> - Allow multiplication of any two units (return type Double)
>
> I came up with the following program using abstract type members, but
> still struggling to find solution using type parameters/generics. Will
> appreciate any help/guidance. Thanks.

See:

http://svn.assembla.com/svn/metascala/src/metascala/Units.scala

/Jesper Nordenberg


Re: [scala] What is the equivalent of this program using type parameters?

by Mushtaq Ahmed :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


why do you want a solution using type parameters?

I'm not sure you'll find one that is more elegant than
one using type members

Luc


I always found parameterized types (especially with variance annotations) difficult to apply. This is an attempt to translate a known solution to a familiar problem... in the hope that the process will make these concepts easier to understand, maybe. 

Re: [scala] Re: What is the equivalent of this program using type parameters?

by Mushtaq Ahmed :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Thanks for the pointer, Jesper. It seems too challenging for my abilities. Will keep it as a reference to gain some wisdom.

Re: [scala] Re: What is the equivalent of this program using type parameters?

by Jim McBeath-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, Oct 16, 2009 at 10:42:14PM +0530, Mushtaq Ahmed wrote:
>      See:
>      http://svn.assembla.com/svn/metascala/src/metascala/Units.scala
>      /Jesper Nordenberg
>
>    Thanks for the pointer, Jesper. It seems too challenging for my
>    abilities. Will keep it as a reference to gain some wisdom.

See
<http://jim-mcbeath.blogspot.com/2008/11/practical-church-numerals-in-scala.html>,
for a slightly simpler example with detailed explanation.

By the way, Jesper, I believe your definition of / in Units.scala
needs a / not * near the end of the line.

--
Jim

[scala] Re: What is the equivalent of this program using type parameters?

by Jesper Nordenberg :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Jim McBeath wrote:
> By the way, Jesper, I believe your definition of / in Units.scala
> needs a / not * near the end of the line.

Good catch :)

/Jesper Nordenberg