Почему 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]]()

Я вижу неявную карту для Semigroup, но не вижу ее для List или Seq.

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

  1. Где неявный для ListSemigroup?
  2. Почему его нет для Seq?

person coltfred    schedule 25.03.2013    source источник
comment
Какую версию ты используешь? Ваши теги предполагают, что вы спрашиваете о scalaz-seven, а ссылка на Semigroup.scala ведет к мастеру, то есть 6.x.   -  person folone    schedule 26.03.2013
comment
Я действительно использую 7. Исправлю свою ссылку.   -  person coltfred    schedule 26.03.2013


Ответы (1)


Итак, в Scalaz 7 есть неявная функция List в Monoid, которая возвращает вам Monoid[List[A]]. Monoid расширяет SemiGroup, поэтому у нас есть список.

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

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

ОБНОВЛЕНИЕ

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

person Noah    schedule 25.03.2013
comment
Отличный ответ на вопрос о том, где он находится в списке. Кажется, все итерации должны быть как минимум полугруппами ... - person coltfred; 26.03.2013
comment
Если вы посмотрите на scala doc, Seq является базой для LinearSeq и IndexedSeq, которые имеют разные различия в производительности. List наследует LinearSeq, поэтому я понимаю, почему им пришлось выбрать List и IndexedSeq вместо Seq. Я посмотрю, смогу ли я обновить это более кратко. - person Noah; 26.03.2013
comment
В дополнение к тому, что здесь уже сказано, вы можете взглянуть на этот пример: github.com/scalaz/scalaz/blob/ Он использует Isomorphism для получения экземпляров для Seq из List. Используйте его на свой страх и риск: по словам Джейсона Заугга, экземпляры для Seq опасны. - person folone; 02.04.2013