Почему List является полугруппой, а Seq нет?
Я довольно новичок в скалазе и пытаюсь понять, почему работает следующий код:
import scalaz._
import Scalaz._
scala> Map[String,List[String]]() |+| Map[String,List[String]]()
res3: scala.collection.immutable.Map[String,List[String]] = Map()
но это не...
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]]()
Я вижу карту, неявную для полугруппы, но я не вижу карту для List или Seq.
Пара вопросов:
- Где неявное для ListSemigroup?
- Почему там нет для Seq?
1 ответ
Итак, в Scalaz 7 есть неявное List
в Monoid
функция, которая дает вам обратно Monoid[List[A]]
, Monoid
продолжается SemiGroup
так что у нас есть список покрыты.
Seq
не получает это специальное лечение. Там нет неявного преобразования из Seq
в Monoid
или же Semigroup
, Есть неявное IndexedSeq
в Monoid
, но это не помогает нам.
Почему там нет для Seq? Я не знаю. Возможно, Seq нарушает некоторые законы моноидов / полугрупп, поэтому нет преобразования. Похоже, что были проблемы с Seq в Scalaz 6, поэтому они удалили некоторые функции: https://groups.google.com/forum/?fromgroups=
ОБНОВИТЬ
Глядя на документ Scala, становится более очевидным, почему люди из скала пошли по этому пути. Список наследует LinearSeq, который наследует Seq. IndexedSeq наследует Seq. Если бы они предоставили полугруппу для Seq, она могла бы переопределить любую другую полугруппу в IndexedSeq или LinearSeq и потерять преимущества в производительности между ними. Если вы посмотрите на сигнатуры скаляза для добавления, вы увидите, что они используют эти различия в производительности:
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
}
Если мы копаем глубже, то увидим, что Seq реализует только ++, который имеет худшую производительность в списках, чем ::: для операций добавления. Итак, чтобы ответить на ваш второй вопрос, производительность. Если в Scazaz реализована полугруппа для Seq, это, скорее всего, приведет к неоднозначной производительности, поскольку вы сможете оптимизировать только для индексированных. Итерируемый имеет ту же проблему.