scala implicit-conversion

scala - Intersección de múltiples conversiones implícitas: ¿reinventar la rueda?



implicit-conversion (1)

De acuerdo, advertencia justa: este es un seguimiento de mi ridícula pregunta de la semana pasada. Aunque creo que esta pregunta no es tan ridícula. De todos modos, aquí va:

Pregunta anterior ridícula:

Supongamos que tengo un rasgo base T con las subclases A , B y C , puedo declarar una colección Seq[T] por ejemplo, que puede contener valores de tipo A , B y C Haciendo el subtipado más explícito, usemos la sintaxis del tipo Seq[_ <: T] .

Ahora suponga que tengo una clase de clase TC[_] con miembros A , B y C (donde "miembro" significa que el compilador puede encontrar algo de TC[A] , etc. en alcance implícito). Al igual que en el ejemplo anterior, deseo declarar una colección de tipo Seq[_ : TC] , utilizando la sintaxis del contexto.

Esto no es legal Scala, y tratar de emular puede hacerte sentir como una mala persona . Recuerde que la sintaxis del contexto (¡cuando se usa correctamente!) Desciende a una lista de parámetros implícita para la clase o método que se está definiendo, lo cual no tiene ningún sentido aquí.

Nueva premisa:

Así que supongamos que las instancias de clase de tipo (es decir, los valores implícitos) están descartadas, y en su lugar debemos usar conversiones implícitas en este caso. Tengo algún tipo V (se supone que la "v" representa "ver", fwiw), y las conversiones implícitas en el alcance A => V , B => V y C => V Ahora puedo completar una Seq[V] , a pesar de que A , B y C no están relacionados.

Pero, ¿qué sucede si quiero una colección de elementos que sean implícitamente convertibles tanto para las vistas V1 como para las V2 ? No puedo decir Seq[V1 with V2] porque mis conversiones implícitas no se agregan mágicamente de esa manera.

Intersección de conversiones implícitas

Resolví mi problema así:

// 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))

Ahora puedo escribir Seq[V1 & V2] como un jefe. Por ejemplo:

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")

Las conversiones implícitas de String e Int para escribir Foo & Bar ocurren cuando se llena la secuencia, y luego las conversiones implícitas de Foo & Bar a Foo y Bar ocurren al llamar a foobar.foo y foobar.bar .

La (s) pregunta (s) ridícula (s) actual (es):

  1. ¿Alguien ha implementado este patrón en algún lugar antes, o soy el primer idiota en hacerlo?
  2. ¿Hay una manera mucho más simple de hacer esto que me he perdido a ciegas?
  3. Si no, ¿cómo implementaría una plomería más general, de modo que pueda escribir Seq[Foo & Bar & Baz] ? Esto parece un trabajo para HList ...
  4. Bonificación extra mega combo: al implementar la plomería más general, ¿puedo restringir los tipos para que sean únicos? Por ejemplo, me gustaría prohibir Seq[Foo & Foo] .

El apéndice de falla:

Mi último intento (esencia) . No es terrible, pero hay dos cosas que no me gustan allí:

  • La sintaxis Seq[All[A :: B :: C :: HNil]] (Quiero que las cosas HList sean opacas, y prefiera Seq[A & B & C] )
  • La anotación de tipo explícita ( abc[A].a ) requerida para la conversión. Parece que puede tener inferencia de tipo o conversiones implícitas, pero no ambas ... No pude encontrar la forma de evitarlo, de todos modos.