visual sumar significado para lista comandos codigos codificacion botones scala scala-option

scala - sumar - comandos de visual basic



Scala: Hacer que la conversión implícita A-> B funcione para la Opción[A]-> Opción (5)

Aquí hay una pista:

scala> val fooOpt: Option[Bar] = Option(Foo(1)) fooOpt: Option[Bar] = Some(Bar(1))

Y otro:

scala> implicit def foobar(x: String): Int = augmentString(x).toInt foobar: (x: String)Int scala> val y: Option[String] = Option(1) y: Option[String] = Some(1) scala> val y: Option[Int] = Option("1") y: Option[Int] = Some(1)

Parece un error legítimamente extraño . Me gustaría abrir un caso de prueba más pequeño y abrir un problema (o buscar uno en JIRA).

Como un aparte:

Podría usar alguna teoría de categorías para manejar muchos tipos diferentes de cosas "Option-ish".

package object fun { trait Functor[Container[_]] { def fmap[A,B](x: Container[A], f: A => B): Container[B] } object Functor { implicit object optionFunctor extends Functor[Option] { override def fmap[A,B](x: Option[A], f: A => B): Option[B] = x map f } // Note: With some CanBuildFrom magic, we can support Traversables here. } implicit def liftConversion[F[_], A, B](x: F[A])(implicit f: A => B, functor: Functor[F]): F[B] = functor.fmap(x,f) }

Eso es un poco más avanzado, ya que está mapeando un poco de teoría de categorías FP en el problema, pero es una solución más general para elevar las conversaciones implícitas en contenedores según sea necesario. Observe cómo se encadenan utilizando un método de conversación implícito que toma un argumento implícito más limitado.

ADEMÁS, esto debería hacer que los ejemplos funcionen:

scala> val tmp = Option(Foo(1)) tmp: Option[Foo] = Some(Foo(1)) scala> val y: Option[Bar] = tmp y: Option[Bar] = Some(Bar(1))

Y haz tu uso de Some más peligrosos:

scala> val tmp = Some(Foo(1)) tmp: Some[Foo] = Some(Foo(1)) scala> val y: Option[Bar] = tmp <console>:25: error: could not find implicit value for parameter functor: fun.Functor[Some] val y: Option[Bar] = tmp ^

Eso te dice que la varianza es crítica e interactúa con implicaciones. Supongo que te encuentras con un error muy raro, probablemente difícil de solucionar, que puedes evitar usando otras técnicas.

Estoy intentando escribir una función que reutiliza las conversiones implícitas que tengo para el Objeto A -> Objeto B cuando están envueltas en una Opción de una manera genérica para que las conversiones de la Opción [A] -> Opción [B] también trabajo.

Lo que he encontrado es:

implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_))

Esto funciona cuando asigno un Some (..) a un valor pero no cuando asigno un Option val; ver la siguiente salida de consola:

scala> trait T defined trait T scala> case class Foo(i: Int) extends T defined class Foo scala> case class Bar(i: Int) extends T defined class Bar scala> implicit def fromFooToBar(f: Foo):Bar = Bar(f.i) fromFooToBar: (f: Foo)Bar scala> implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i) fromBarToFoo: (b: Bar)Foo scala> implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_)) fromOptionToOption: [A, B](from: Option[A])(implicit conversion: (A) => B)Option[B] scala> val foo: Option[Foo] = Some(Bar(1)) foo: Option[Foo] = Some(Foo(1)) // THIS WORKS as expected scala> val fooOpt = Some(Foo(4)) fooOpt: Some[Foo] = Some(Foo(4)) scala> val barOpt2: Option[Bar] = fooOpt <console>:16: error: type mismatch; found : Some[Foo] required: Option[Bar] val barOpt2: Option[Bar] = fooOpt ^ //THIS FAILS.

Realmente no veo la diferencia entre la primera y la segunda conversión. De alguna manera no invoca la conversión implícita en este último. Supongo que tiene algo que ver con el sistema de tipos, pero no puedo ver cómo todavía. ¿Algunas ideas? -Albert (estoy en scala 2.9.1)


De hecho es un problema muy extraño. Intenté usar otro tipo que no sea la Option , y resulta que el problema es que la Option es covariante en su parámetro de tipo. Esto funciona todo:

case class A[B](value: B) // invariant in B case class X() case class Y() implicit def xtoy(x: X): Y = Y() implicit def ytox(x: Y): X = X() implicit def movea[U, V](from: A[U])(implicit view: U => V): A[V] = A[V](from.value) def test(a: A[Y]) = "ok" test(A(X())) // (1) val f = A(X()) test(f) // (2)

Pero si por el contrario defino a A como

case class A[+B](value: B) // covariant in B

El caso (2) falla. El caso (1) siempre tiene éxito, porque Scala ya convierte X en Y antes de envolverlo en una A

Ahora que conocemos la fuente del problema, debe esperar a que un gurú de los tipos explique por qué esto es realmente un problema ... La conversión sigue siendo válida, como ve:

askForY(movea(f)) // succeeds, even with A[+B]


No funciona porque la especificación de lenguaje Scala define la vista de la siguiente manera:

Los parámetros y métodos implícitos también pueden definir conversiones implícitas llamadas vistas . Una vista del tipo S al tipo T se define por un valor implícito que tiene el tipo de función S => T o (=> S) => T o por un método convertible a un valor de ese tipo.

fromOptionToOption no se ajusta a las tres categorías, ya que toma un parámetro implícito. El compilador no parece encontrar un convertidor con el destino y la fuente con un tipo genérico.

La definición de una vista desde la Option[Foo] a la Option[Bar] funciona como se espera.

trait T case class Foo(i: Int) extends T case class Bar(i: Int) extends T object Main { implicit def fromFooToBar(f: Foo):Bar = Bar(f.i) implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i) // implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = // from.map(conversion(_)) implicit def fromOptionFooToOptionBar(o: Option[Foo]): Option[Bar] = o map { foo => foo } def test(): Option[Bar] = { val fooOpt = Some(Foo(4)) val barOpt2: Option[Bar] = fooOpt barOpt2 } } println(Main.test)

Ejecutando esto imprime:

$ scala so.scala Some(Bar(4))

Sin embargo, no todo está perdido. No es tan bueno como la Option a Option general, pero podemos hacer algo como lo que puede convertirse en Bar a Option[Bar] por vista enlazada.

trait T case class Foo(i: Int) extends T case class Bar(i: Int) extends T object Main { implicit def fromFooToBar(f: Foo):Bar = Bar(f.i) implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i) implicit def fromOptionToOptionBar[A <% Bar](from: Option[A]): Option[Bar] = from map { foo => foo } def test(): Option[Bar] = { val fooOpt = Some(Foo(4)) val barOpt2: Option[Bar] = fooOpt barOpt2 } } println(Main.test)

Aquí hay otra solución que se puede usar para la Option general a Option pero que requiere una llamada extra .convert :

trait T case class Foo(i: Int) extends T case class Bar(i: Int) extends T case class Converter[A](x: Option[A]) { def convert[B](implicit ev: Function1[A, B]): Option[B] = x map { a: A => ev(a) } } object Main { implicit def optionToConverter[A](x: Option[A]) = Converter(x) implicit def fooToBar(x: Foo) = Bar(x.i) def test(): Option[Bar] = { val fooOpt = Some(Foo(4)) val barOpt: Option[Bar] = fooOpt.convert barOpt } } println(Main.test)


Puede que no lo sepas, pero hay un indicador para eso: -Xlog-implicits . Y esto es lo que dice:

scala> val barOpt2: Option[Bar] = fooOpt fromOptionToOption is not a valid implicit value for Some[Foo] => Option[Bar] because: incompatible: (from: Option[Foo])(implicit conversion: Foo => B)Option[B] does not match expected type Some[Foo] => Option[Bar] <console>:16: error: type mismatch; found : Some[Foo] required: Option[Bar] val barOpt2: Option[Bar] = fooOpt ^

Y ahí tienes, no sabe qué tipo B debe ser. 0__ mencionó que este problema no ocurre con las colecciones invariantes, y eso tiene algún sentido. En colecciones invariantes, B debe ser exactamente Bar , mientras que para colecciones covariantes podría ser cualquier subtipo de Bar .

Entonces, ¿por qué val foo: Option[Foo] = Some(Bar(1)) funciona? Bueno, hay una bandera para eso también ... -Ytyper-debug . No para los débiles, sin embargo, dada la extrema verbosidad.

Caminé a través de todos modos, comparando lo que sucede en ambos casos, y la respuesta es bastante simple ... no es la Option que se está convirtiendo en ese caso, ¡sino Bar ! ¡Recuerda que declaraste una conversión implícita de Bar => Foo , por lo que está aplicando esa conversión antes de pasar el resultado a Some !


Mejoré la respuesta de @jseureth y agregué soporte para Traversable :

trait Mappable[A, B, C[_]] { def apply(f: A => B): C[B] } package object app { implicit class OptionMappable[A, B, C[X] <: Option[X]](option: C[A]) extends Mappable[A, B, Option] { override def apply(f: A => B): Option[B] = option.map(f) } implicit class TraversableMappable[A, B, C[X] <: Traversable[X]](traversable: C[A]) (implicit cbf: CanBuildFrom[C[A], B, C[B]]) extends Mappable[A, B, C] { override def apply(f: A => B): C[B] = { val builder = cbf(traversable) builder.sizeHint(traversable) builder ++= traversable.map(f) builder.result() } } implicit def liftConversion[C[_], A, B](x: C[A]) (implicit f: A => B, m: C[A] => Mappable[A, B, C]): C[B] = m(x)(f) }

Ahora puedes convertir implícitamente las opciones y los traversables:

implicit def f(i: Int): String = s"$i" val a: Option[String] = Some(1) val b: Seq[String] = Seq(1, 2, 3)