Я работаю над небольшой библиотекой для экономических моделей, которые проверяют единицы объектов, используя типы, например. вместо val apples = 2.0
пишем val apples = GoodsAmount[KG, Apples](2.0)
. Для создания пачки товаров я пытался использовать HLists из библиотеки shapeless. Это нормально работает, но в некоторых случаях я не могу использовать такой общий код, как я предпочитаю. См., Например, следующая проблема.
Я начинаю с простого кода, который объясняет, что я хочу превратить в бесформенное. Мы создаем два класса, один из которых представляет Km, а другой - Miles. Следует разрешить добавление классов км, но не миль. То, что я использую абстрактный тип 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 */
}
Это работает как задумано. Но необходимо иметь проверку Type 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 и где я мог бы добавить параметр неявного доказательства. И я также не знаю, что я должен сделать, чтобы Картограф нашел свое неявное значение.
Менее общая версия, в которой я заменяю функцию caseTuple на
implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b }
работает нормально, но потребуется написать много избыточного кода (хорошо, это решение было бы все же лучше, чем наше текущее решение с использованием кортежей). Может кто-нибудь подскажет, как я могу решить эту проблему?
Спасибо, клинке
Foo
следующим образом:trait Foo[T <: Foo] { v: Double; +(t T): T =...}
.class Km(val v: Double) extends Foo[Km]
.implicit def add[T] = at[(Foo[T], Foo[T])]
- person senia   schedule 27.06.2013