Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type inference/type checking failure while using type-level computations

I have hit a problem while working with the Units of Measurements functionality in metascala, defined in the file Units.scala.

For the remainder of this question, I will use a simplified scheme, with only one Unit type, length.

So where in reality a type looks like

Quantity[_1, _0, _0, _0, _0, _0, _0] 
          ^   ^   ^   ^   ^   ^   ^
          |   |   |   |   |   |   |
          | Mass  | Crncy.|  Mol  |
       Length   Time    Temp. Lum.Intensity

this will be sufficient for demonstrating the problem:

Quantity[_1]
          ^
          |
       Length

As soon as the type needs to be inferred, the trouble starts.

Consider this example (also have a look at the code from UnitsTest.scala):

val length: Quantity[_1] = m(5)
val area:   Quantity[_2] = length * length // (1) Works
val dist:   Quantity[_1] = area / length   // (2) Doesn't work!

I get an error in the last line saying:

type mismatch;
  found :
    scalax.units.Units.Quantity[
      scalax.units.Subtractables.-[
        scalax.units.Integers._2,
        scalax.units.Integers._1
      ]
    ]

  required:
    scalax.units.Units.Quantity[
      scalax.units.Integers._1
    ]

It looks like the compiler can't figure out that the type at hand is equal to Quantity[_1] when "substracting a dimension", e. g. going from area to dist like in (1):

Quantity[_2 - _1] <<not equal to>> Quantity[_1]

The confusing thing is that it works when "adding a dimension" e. g. going from length to area like in (2):

Quantity[_1 + _1] <<equal to>> Quantity[_2]

(Sorry for not pasting the whole code here, it is just too much. I tried to minimize my example, but I failed. That's why I'm just linking to it.)

like image 986
soc Avatar asked Oct 21 '11 19:10

soc


1 Answers

Type Sub from Subtractable is missing in the MInt trait. A simple definition to make it work would be to perform a negative addition when you want to subtract a type in MSucc and MNeg.

sealed trait MInt extends Visitable[IntVisitor] with Addable with Subtractable {
  type AddType = MInt
  type SubType = MInt
  type Add[I <: MInt] <: MInt
  type Sub[I <: MInt] <: MInt
  type Neg <: MInt
  type Succ <: MInt
  type Pre <: MInt
}

final class _0 extends Nat {
  type Add[I <: MInt] = I
  type Sub[I <: MInt] = I#Neg
  type AcceptNatVisitor[V <: NatVisitor] = V#Visit0
  type Neg = _0
  type Succ = MSucc[_0]
  type Pre = Succ#Neg
}

final class MSucc[P <: Nat] extends Pos {
  type This = MSucc[P]
  type Add[N <: MInt] = P#Add[N]#Succ
  type Sub[N <: MInt] = Add[N#Neg]
  type AcceptNatVisitor[V <: NatVisitor] = V#VisitSucc[P]
  type Neg = MNeg[This]
  type Pre = P
  type Succ = MSucc[This]
}

final class MNeg[P <: Pos] extends MInt {
  type Add[N <: MInt] = P#Add[N#Neg]#Neg
  type Sub[N <: MInt] = Add[N#Neg]
  type Accept[V <: IntVisitor] = V#VisitNeg[P]
  type Neg = P
  type Succ = P#Pre#Neg
  type Pre = P#Succ#Neg
}

One more thing, the / method in Quantity should divide its parameters and not multiply them!

like image 80
Mark Jayxcela Avatar answered Oct 11 '22 17:10

Mark Jayxcela