tutorial listas funciones español ejemplos scala shapeless

listas - Cómo agregar o anteponer un elemento a una tupla en Scala



scala ejemplos (4)

Encontré una solución con la ayuda de la increíble biblioteca Shapeless y es HList

/* Define an implicit class to add the methods It accepts any tuple as we have typed it as Product */ implicit class TupleOps[A <: Product](t: A) { /* Declare the method to append B - The type of element we want to append L - The HList representing the tuple A P - The HList after appending B R - The final result */ def :+[B, L <: HList, P <: HList, R <: Product](b: B)( /* We need some tools to help with the conversion hlister - Converts a tuple into an HList prepend - Can prepend one HList before another tupler - Can convert an HList into a tuple */ implicit hlister: HListerAux[A, L], prepend: PrependAux[L, B :: HNil, P], tupler: TuplerAux[P, R]):R = // Let the helpers do their job tupler(prepend(hlister(t), b :: HNil)) /* The prepend method is similar to the append method but does not require the extra effort to append */ def +:[B, L <: HList, R <: Product](b: B)( // Here we use the :: type of shapeless implicit hlister: HListerAux[A, L], tupler: TuplerAux[B :: L, R]):R = tupler(b :: hlister(t)) } // usage is like this ("", 1, 1f) :+ 1d //> res0: (String, Int, Float, Double) = ("",1,1.0,1.0) 1d +: ("", 1, 1f) //> res1: (Double, String, Int, Float) = (1.0,"",1,1.0)

Editar

En algunos casos, cuando necesite lidiar con conversiones implícitas, esta solución no funcionará en combinación con clases de casos. Ahora volví a la siguiente implementación (basada en el código de Rex Kerr)

def char(n: Int) = (''A'' + n).toChar def prop(n: Int) = "t._" + (n + 1) val result = for (n <- 1 to 21) yield { val range = (0 until n) val tupleTypeParams = range map char mkString ", " val tupleProperties = range map prop mkString ", " val elementType = char(n) val elementProperty = prop(n) val first = n == 1 val tupleType = if (first) s"Tuple1[$tupleTypeParams]" else s"($tupleTypeParams)" val tupleInstance = if (first) s"Tuple1($tupleProperties)" else s"($tupleProperties)" val resultType = s"($tupleTypeParams, $elementType)" s"""|implicit def tupleOps$n[$tupleTypeParams, $elementType] = | new TupleAppendOps[$tupleType, $elementType, $resultType] { | def append(t: $tupleType, e: $elementType) = ($tupleProperties, e) | def init(t: $resultType) = $tupleInstance | def last(t: $resultType) = $elementProperty | }""".stripMargin } println(result mkString "/n")

Tengo una tupla y quiero agregar un elemento sin perder el tipo de seguridad. Esto es lo que quiero lograr:

val tuple = ("", 1, 1f) // (String, Int, Float) val newTuple:(String, Int, Float, Double) = tuple :+ 1d


Puede probar mi biblioteca de macros experimentales basada en la rama de Scala de macro paradise en https://github.com/leonardschneider/macrogen que hace exactamente su ejemplo.

En este momento todavía tengo algunos errores, sin embargo, no puedo encadenar las llamadas.


Sin forma ahora hace el truco. Añadiendo

import shapeless.syntax.std.tuple._

antes de que tu código simplemente compile.


Vale la pena señalar que también puede escribir un generador de código para esto en unas pocas líneas:

val tupadd = for (n <- 2 to 20) yield { val t = (0 until n).map(i => (''A''+i).toChar).mkString(", ") val u = (''A''+n).toChar val i = (0 until n).map(i => "x._"+(i+1)).mkString(", ") List( s"implicit class TupOps$n[$t](val x: ($t)) extends AnyVal {", s" def :+[$u](y: $u) = ($i, y)", s" def +:[$u](y: $u) = (y, $i)", "}" ).mkString("/n") }

Imprime estos, pégalos en un archivo y listo:

scala> implicit class TupOps2[A, B](val x: (A, B)) extends AnyVal { | def :+[C](y: C) = (x._1, x._2, y) | def +:[C](y: C) = (y, x._1, x._2) | } defined class TupOps2 scala> (1,"salmon") :+ true res15: (Int, String, Boolean) = (1,salmon,true)