#generics #scala #types #alias #units-of-measurement
#обобщения #scala #типы #псевдоним #единицы измерения
Вопрос:
Я столкнулся с проблемой при работе с функциональностью единиц измерения в метаскале, определенной в файле Units.scala.
Для остальной части этого вопроса я буду использовать упрощенную схему, содержащую только один тип единицы измерения, length .
Итак, где на самом деле выглядит тип
Quantity[_1, _0, _0, _0, _0, _0, _0]
^ ^ ^ ^ ^ ^ ^
| | | | | | |
| Mass | Crncy.| Mol |
Length Time Temp. Lum.Intensity
этого будет достаточно для демонстрации проблемы:
Quantity[_1]
^
|
Length
Как только требуется определить тип, начинаются проблемы.
Рассмотрим этот пример (также взгляните на код из 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!
В последней строке я получаю сообщение об ошибке:
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
]
Похоже, что компилятор не может определить, что тип под рукой равен Quantity[_1]
, когда «вычитается измерение», например, переход от area к dist, как в (1)
:
Quantity[_2 - _1] <<not equal to>> Quantity[_1]
Сбивает с толку то, что это работает при «добавлении измерения», например, при переходе от длины к площади, как в (2)
:
Quantity[_1 _1] <<equal to>> Quantity[_2]
(Извините, что не вставил сюда весь код, это слишком много. Я попытался свести к минимуму свой пример, но мне это не удалось. Вот почему я просто ссылаюсь на него.)
Ответ №1:
Тип Sub
from Subtractable
отсутствует в MInt
черте. Простым определением, позволяющим заставить его работать, было бы выполнить отрицательное сложение, когда вы хотите вычесть тип в MSucc
и 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
}
Еще одна вещь, /
метод в Quantity
должен разделять свои параметры, а не умножать их!
Комментарии:
1. Да, это исправление. Я внес два исправления в репозиторий MetaScala.