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):
- ¿Alguien ha implementado este patrón en algún lugar antes, o soy el primer idiota en hacerlo?
- ¿Hay una manera mucho más simple de hacer esto que me he perdido a ciegas?
- 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 paraHList
... - 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 cosasHList
sean opacas, y prefieraSeq[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.
Puedo dar una respuesta parcial para el punto 4. Esto se puede obtener aplicando una técnica como:
http://vpatryshev.blogspot.com/2012/03/miles-sabins-type-negation-in-practice.html