Я работаю над небольшой библиотекой для экономических моделей, которая проверяет единицы объектов, используя типы, например. вместо val apples = 2.0
пишем val apples = GoodsAmount[KG, Apples](2.0)
. Для создания пакета товаров я пытаюсь использовать HLists из бесформенной библиотеки. Это прекрасно работает, но в некоторых случаях я не могу быть таким же общим кодом, как я предпочел. См. следующая проблема.Безшовное: проверка типов ограничений полиморфных функций
Я начинаю с простого кода, который объясняет, что я хочу снять в бесформенный. Мы создаем два класса, на которых изображены Km, другие Мили. Должно быть разрешено добавлять классы Km, но не мили. То, что я использую абстрактный тип T, в основном мотивируется нашей более сложной библиотекой. И косвенный вызов функции «+» заключается только в том, что нам нужно что-то подобное в бесформенном случае.
trait Foo {
type T
val v: Double
def +[B <: Foo](other: B)(implicit ev: this.T =:= other.T) = v + other.v
}
trait _Km
trait _Miles
case class Km(v: Double) extends Foo { type T = _Km }
case class Miles(v: Double) extends Foo { type T = _Miles }
object ExampleSimple extends App {
def add[A <: Foo, B <: Foo](a: A, b: B)(implicit ev: a.T =:= b.T) = { a + b }
add(Km(1), Km(2))
// add(Km(1), Miles(2)) /* does not compile as intended */
}
Это работает по назначению. Но для функции «добавить» необходимо иметь проверку типа Contraint. Моя попытка распространить это на HLists выглядит следующим образом:
object ExampleShapeless extends App {
import shapeless._
val l1 = Km(1) :: Km(2) :: HNil
val l2 = Km(4) :: Km(3) :: HNil
object add extends Poly1 {
implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a, b) => a + b }
}
(l1 zip l2).map(add)
}
Но генерировать следующее сообщение об ошибке (с помощью Scala 2.10.2):
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:50: Cannot prove that a.T =:= b.T.
[error] implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a: Foo, b) => a + b }
[error] ^
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:54: could not find implicit value for parameter mapper: shapeless.Mapper[ExampleShapeless.add.type,shapeless.::[(Km, Km),shapeless.::[(Km, Km),shapeless.HNil]]]
[error] (l1 zip l2).map(add)
должен быть закреплен Первая ошибка, в случае что я могу добавить ограничение типа к функции caseTuple, но, честно говоря, я не понял, как работает функция at и где я могу добавить параметр неявных доказательств. И я также не знаю, что я должен делать, чтобы Mapper нашел его неявное значение.
Менее общий вариант, где я replase функцию caseTuple с
implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b }
работает отлично, но нужно будет написать много избыточного кода (хорошо, это решение было бы еще лучше, так как наше нынешнее решение с использованием Кортежи). Может ли кто-нибудь дать мне подсказку, как я могу решить эту проблему?
Спасибо, KLINKE
Вы можете попытаться определить ваш 'Foo' следующим образом:' trait Foo [T <: Foo] {v: Double; + (t T): T = ...} '. 'class Km (val v: Double) расширяет Foo [Km]'. 'implicit def add [T] = at [(Foo [T], Foo [T])]' – senia