Подтвердить что ты не робот

Пересечение нескольких неявных преобразований: изобретать колесо?

Хорошо, справедливое предупреждение: это продолжение моего смешного вопроса с прошлой недели. Хотя я думаю, что этот вопрос не такой уж смешной. В любом случае, здесь идет:

Предыдущий смешной вопрос:

Предположим, что у меня есть базовый признак T с подклассами A, B и C, я могу, например, объявить коллекцию Seq[T], которая может содержать значения типа A, B и C. Чтобы сделать подтипирование более явным, используйте синтаксис типа Seq[_ <: T].

Теперь вместо этого предположим, что у меня есть typeclass TC[_] с членами A, B и C (где "член" означает, что компилятор может найти некоторые TC[A] и т.д. в неявной области). Как и выше, я хочу объявить коллекцию типа Seq[_ : TC], используя синтаксис с привязкой к контексту.

Это не является законным Scala, и попытка эмулировать может заставить вас чувствовать себя плохой человек. Помните, что связанный с контекстом синтаксис (при использовании правильно!) Desugars в список неявных параметров для определяемого класса или метода, что здесь не имеет никакого смысла.

Новое помещение:

Итак, допустим, что экземпляры typeclass (т.е. неявные значения) не могут быть и речи, и вместо этого нам нужно использовать неявные преобразования в этом случае. У меня есть какой-то тип V (предполагается, что "v" означает "вид", 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 возникают при заполнении последовательности, а затем при вызове foobar.foo и затем неявные преобразования от Foo & Bar до Foo и Bar foobar.bar.

Нынешний смешной вопрос (ы):

  • Кто-нибудь реализовал этот шаблон раньше, или я первый идиот, чтобы сделать это?
  • Есть ли более простой способ сделать это, о котором я слепо пропустил?
  • Если нет, то как мне применить более общую сантехнику, чтобы я мог написать Seq[Foo & Bar & Baz]? Это похоже на работу для HList...
  • Дополнительный мега-бонус: при реализации более общей сантехники я могу ограничить типы уникальными? Например, я хотел бы запретить Seq[Foo & Foo].

Приложение сбоя:

Моя последняя попытка (gist). Не страшно, но есть две вещи, которые мне не нравятся:

  • Синтаксис Seq[All[A :: B :: C :: HNil]] (я хочу, чтобы материал HList был непрозрачным и предпочитал Seq[A & B & C])
  • Явная аннотация типа (abc[A].a), необходимая для преобразования. Похоже, вы можете либо иметь вывод типа, либо неявные преобразования, но не оба... Я никак не мог понять, как его избежать.
4b9b3361