Подтвердить что ты не робот

Почему List - полугруппа, но Seq - нет?

Я новичок в scalaz, и я пытаюсь понять, почему работает следующий код:

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]]()

Я вижу, что Map неявна для Semigroup, но я не вижу ее для List или Seq.

Пара вопросов:

  • Где подразумевается для ListSemigroup?
  • Почему нет Seq?
4b9b3361

Ответ 1

Итак, в Scalaz 7 существует неявная List to Monoid функция, которая возвращает вам Monoid[List[A]]. Monoid extends SemiGroup, поэтому мы включили Список.

Seq не получает этого специального лечения. Нет никакого неявного преобразования от Seq до Monoid или SemiGroup. Существует неявный IndexedSeq до Monoid, но это не помогает нам.

Почему нет Seq? Я не знаю. Возможно, Seq нарушает некоторые законы моноидов/полугрупп, поэтому конверсия отсутствует. Похоже, были проблемы с Seq в Scalaz 6, поэтому они убрали некоторые функции: https://groups.google.com/forum/?fromgroups=#!searchin/scalaz/Seq/scalaz/Deaec1H11W4/gYFSquXjTzYJ

UPDATE

Глядя на документ scala, становится все более очевидным, почему люди скасаза пошли таким образом. List наследует LinearSeq, который наследует Seq. IndexedSeq наследует Seq. Если бы они предоставили полугруппу для Seq, она могла бы переопределить любую другую полугруппу на IndexedSeq или LinearSeq и потерять преимущества производительности между ними. Если вы посмотрите на подписи scalaz для добавления, вы увидите, что они используют преимущества этих различий в производительности:

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 реализует ++, который имеет худшую производительность в списках, чем : для операций добавления. Итак, чтобы ответить на ваш второй вопрос, производительность. Если бы scalaz реализовал полугруппу для Seq, это, скорее всего, приведет к неоднозначной производительности, поскольку вы сможете оптимизировать только индексирование. У Iterable такая же проблема.