Хорошо, честное предупреждение: это продолжение моего смешного вопроса с прошлой недели.Хотя я думаю, что этот вопрос не такой смешной.В любом случае, вот что:
Предыдущий нелепый вопрос:
Предположим, у меня есть базовая черта T
с подклассами A
, B
и C
, я могу объявить коллекцию Seq[T]
например, который может содержать значения типа A
, B
и C
.Чтобы сделать подтип более явным, давайте используем синтаксис привязки типа Seq[_ <: T]
.
Теперь вместо этого предположим, что у меня есть класс типов TC[_]
с членами A
, B
и C
(где "member"означает, что компилятор может найти некоторые TC[A]
и т. д. в неявном объеме).Как и выше, я хочу объявить коллекцию типа Seq[_ : TC]
с использованием синтаксиса с привязкой к контексту.
Это недопустимо в Scala, и попытка эмуляции может заставить вас почувствовать себя плохим человеком .Помните, что связанный с контекстом синтаксис (при правильном использовании!) Десагарсирует в неявный список параметров для определяемого класса или метода, который здесь не имеет никакого смысла.
Новая предпосылка:
Итакдавайте предположим, что экземпляры класса типов (т.е. неявные значения) исключены, и вместо этого нам нужно использовать неявные преобразования в этом случае.У меня есть тип V
(«v» означает «view», «fwiw») и неявные преобразования в области A => V
, B => V
и C => V
.Теперь я могу заполнить Seq[V]
, несмотря на то, что A
, B
и C
никак не связаны.
Но что, если я хочу, чтобы набор вещей, которые были неявно преобразованы в представления V1
и V2
?Я не могу сказать Seq[V1 with V2]
, потому что мои неявные преобразования таким образом магически не агрегируют.
Пересечение неявных преобразований?
Я решил свою проблему следующим образом:
// a sort of product or intersection, basically identical to Tuple2
final class &[A, B](val a: A, val b: B)
// implicit conversions from the product to its member types
implicit def productToA[A, B](ab: A & B): A = ab.a
implicit def productToB[A, B](ab: A & B): B = ab.b
// implicit conversion from A to (V1 & V2)
implicit def viewsToProduct[A, V1, V2](a: A)(implicit v1: A => V1, v2: A => V2) =
new &(v1(a), v2(a))
Теперь я могу написать Seq[V1 & V2]
как босс.Например:
trait Foo { def foo: String }
trait Bar { def bar: String }
implicit def stringFoo(a: String) = new Foo { def foo = a + " sf" }
implicit def stringBar(a: String) = new Bar { def bar = a + " sb" }
implicit def intFoo(a: Int) = new Foo { def foo = a.toString + " if" }
implicit def intBar(a: Int) = new Bar { def bar = a.toString + " ib" }
val s1 = Seq[Foo & Bar]("hoho", 1)
val s2 = s1 flatMap (ab => Seq(ab.foo, ab.bar))
// equal to Seq("hoho sf", "hoho sb", "1 if", "1 ib")
При заполнении последовательности происходят неявные преобразования из String
и Int
в тип Foo & Bar
, а затем неявные преобразования из Foo & Bar
в Foo
и Bar
происходит при вызове foobar.foo
и foobar.bar
.
Текущий нелепый вопрос (-ы):
- Кто-нибудь когда-либо реализовывал этот шаблон раньше или я первый идиот?сделать это?
- Есть ли гораздо более простой способ сделать это, что я слепо пропустил?
- Если нет, то как бы я реализовал более общие слесарные работы, чтобы я мог написать
Seq[Foo & Bar & Baz]
?Это похоже на работу для HList
... - Дополнительный мега-комбо-бонус: при реализации более общего слесарного дела, могу ли я ограничить типы, чтобы они были уникальными?Например, я хотел бы запретить
Seq[Foo & Foo]
.
Приложение неудач:
Моя последняя попытка (суть) .Не страшно, но мне там не нравятся две вещи:
- Синтаксис
Seq[All[A :: B :: C :: HNil]]
(я хочу, чтобы материал HList
был непрозрачным, и предпочел бы Seq[A & B & C]
) - Явная аннотация типа (
abc[A].a
), необходимая для преобразования.Похоже, что вы можете иметь как вывод типа, так и неявные преобразования, но не оба ... Во всяком случае, я не мог понять, как этого избежать.