scala - resueltos - ¿Por qué la Lista es un Semigrupo pero Seq no?
operaciones binarias y sus propiedades pdf (1)
Soy bastante nuevo en Scalaz y estoy tratando de descubrir por qué funciona el siguiente código:
import scalaz._
import Scalaz._
scala> Map[String,List[String]]() |+| Map[String,List[String]]()
res3: scala.collection.immutable.Map[String,List[String]] = Map()
pero esto no ...
import scalaz._
import Scalaz._
scala> Map[String,Seq[String]]() |+| Map[String,Seq[String]]()
<console>:14: error: value |+| is not a member of scala.collection.immutable.Map[String,Seq[String]]
Map[String,Seq[String]]() |+| Map[String,Seq[String]]()
Veo el Mapa implícito para Semigroup, pero no veo el de List o Seq.
Preguntas de pareja:
- ¿Dónde está el implícito para ListSemigroup?
- ¿Por qué no hay uno para Seq?
Entonces, en Scalaz 7 hay una función implícita de List
to Monoid
que te devuelve un Monoid[List[A]]
. SemiGroup
extiende SemiGroup
por lo que tenemos la lista cubierta.
Seq
no recibe este tratamiento especial. No hay conversión implícita de Seq
a Semigroup
o Semigroup
. Existe un IndexedSeq
implícito a IndexedSeq
, pero esto no nos ayuda.
¿Por qué no hay uno para Seq? No lo sé. Quizás Seq viola algunas leyes de monoids / semigroups por lo que no hay conversión. Parece que hubo problemas con Seq en Scalaz 6, por lo que eliminaron algunas funciones: https://groups.google.com/forum/?fromgroups=#!searchin/scalaz/Seq/scalaz/Deaec1H11W4/gYFSquXjTzYJ
ACTUALIZAR
Mirando el scala doc se vuelve más aparente por qué los scalaz se fueron de esta manera. List hereda LinearSeq que hereda Seq. IndexedSeq hereda Seq. Si tuvieran que proporcionar un semigrupo para Seq, podría anular cualquier otro semigrupo en IndexedSeq o LinearSeq y perder ventajas de rendimiento entre los dos. Si observa las firmas scalaz para anexar, puede ver que aprovechan estas diferencias de rendimiento:
https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/std/List.scala
implicit def listMonoid[A]: Monoid[List[A]] = new Monoid[List[A]] {
def append(f1: List[A], f2: => List[A]) = f1 ::: f2
def zero: List[A] = Nil
}
https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/std/IndexedSeq.scala
implicit def ixSqMonoid[A]: Monoid[IxSq[A]] = new Monoid[IxSq[A]] {
def append(f1: IxSq[A], f2: => IxSq[A]) = f1 ++ f2
def zero: IxSq[A] = empty
}
Si profundizamos, vemos que Seq solo implementa ++ que tiene un peor rendimiento en listas que ::: para operaciones de adición. Entonces, para responder a su segunda pregunta, desempeño. Si Scalaz implementó semigroup para Seq, lo más probable es que conduzca a un rendimiento ambiguo, ya que solo podría optimizar para indexado. Iterable tiene el mismo problema.