скаляры Итераторы из скала Итератор - PullRequest
3 голосов
/ 01 января 2011

Я отредактировал приведенный ниже код, так как считаю, что неправильно комбинировал объекты IterV поверх проблемы iter.next.

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

import scalaz._
import Scalaz._
import IterV._

implicit val iteratorEnumerator = new Enumerator[Iterator] {
  def apply[E,A](iter: Iterator[E], i: IterV[E,A]): IterV[E,A] =
    if (iter.isEmpty) i
    else i.fold(done = (acc,input) => i, 
                cont = k => apply(iter, k(El(iter.next))))
}

/* probably incorrect
val iter = Iterator(1,2,3)
println("peek(iter) " + peek(iter).run)
println("peek(iter) " + peek(iter).run)
*/

def peekpeek[E]: IterV[E, (Option[E],Option[E])] = 
  for (a <- peek; b <- peek) yield (a,b)
def peekheadpeek[E]: IterV[E, (Option[E],Option[E],Option[E])] = 
  for (a <- peek; b <- head; c <- peek) yield (a,b,c)

peekpeek(Iterator(1,2,3,4)).run
peekheadpeek(Iterator(1,2,3,4)).run

Возвращает:

res0: (Option[Int], Option[Int]) = (Some(1),Some(2)) 
res1: (Option[Int], Option[Int], Option[Int]) = (Some(1),Some(2),Some(3)) 

Где я ожидал (Some(1),Some(1)) и (Some(1),Some(1),Some(2)).

Я подозреваю, что это связано с iter.next побочным эффектом. Какой лучший способ справиться с этим?

Для сравнения этот , взятый непосредственно из примеров исходного кода с веб-сайта scalaz , работает правильно:

implicit val StreamEnumerator = new Enumerator[Stream] {
  def apply[E, A](e: Stream[E], i: IterV[E, A]): IterV[E, A] = e match {
    case Stream() => i
    case x #:: xs => i.fold(done = (_, _) => i, 
                            cont = k => apply(xs, k(El(x))))
  }
}

Ответы [ 4 ]

3 голосов
/ 02 января 2011

Я думаю, я понял это. Похоже, что это в первую очередь связано с El использованием параметра по имени, который пересчитывает iter.next, а также с тем, как я изначально неправильно вызвал вычисление с двумя разными peek(iter).run. Я переписал перечислитель, чтобы сначала присвоить iter.next значению val (а также сделал его рекурсивным в процессе):

implicit val iteratorEnumerator = new Enumerator[Iterator] {
  @annotation.tailrec
  def apply[E,A](iter: Iterator[E], i: IterV[E,A]): IterV[E,A] = i match {
    case _ if iter.isEmpty => i
    case Done(acc, input) => i
    case Cont(k) => 
      val x = iter.next
      apply(iter, k(El(x)))
  }
}

Тогда:

def peekpeek[A] = 
  for (a1 <- peek[A]; a2 <- peek[A]) yield (a1,a2)
def peekheadpeek[A] = 
  for (a1 <- peek[A]; a2 <- head[A]; a3 <- peek[A]) yield (a1,a2,a3)
def headpeekhead[A] = 
  for (a1 <- head[A]; a2 <- peek[A]; a3 <- head[A]) yield (a1,a2,a3)

peekpeek(Iterator(1,2,3)).run
peekheadpeek(Iterator(1,2,3)).run
headpeekhead(Iterator(1,2,3)).run
length(Iterator.from(1).take(1000000)).run

вернул бы это:

res13: (Option[Int], Option[Int]) = (Some(1),Some(1))
res14: (Option[Int], Option[Int], Option[Int]) = (Some(1),Some(1),Some(2))
res15: (Option[Int], Option[Int], Option[Int]) = (Some(1),Some(2),Some(2))
res16: Int = 1000000
2 голосов
/ 10 февраля 2011

Итераторы ленивы. Побочные эффекты (итератор) и лень не смешиваются. Может быть, это будет правильно:

implicit val iteratorEnumerator = new Enumerator[Iterator] {
  def apply[E,A](iter: Iterator[E], i: IterV[E,A]): IterV[E,A] =
    iter.foldRight(i)((x, y) =>
      y.fold(done = (acc, input) => y,
             cont = k => apply(iter, k(El(x))))
    )
}

Опять же, может и нет. Только источник foldRight будет знать. Побочные эффекты такие.

2 голосов
/ 02 января 2011

Вы правы насчет iter.next, вызывающего побочные эффекты. Я думаю, что вопрос сводится к тому, в чем разница между потоком и итератором. Этот вопрос имеет соответствующую информацию.

0 голосов
/ 01 января 2011

Вы можете избежать побочных эффектов, создав одноразовый итератор размера один:

implicit val iteratorEnumerator = new Enumerator[Iterator] {
  def apply[E,A](iter: Iterator[E], i: IterV[E,A]): IterV[E,A] =
    if (iter.isEmpty) i
    else i.fold(done = (acc,input) => i, 
                cont = k => apply(iter, k(El(iter.take(1).next))))
}
...