2011-01-01 12 views
3

私はiter.nextの問題の上でIterVオブジェクトを誤って組み合わせていたと思うので、以下のコードを編集しました。scalaz Iterator from scala Iterator

私はscalazでIterateeを実験しています。なぜ私は次のように動作しないのでしょうか?ここでは、私が持っているものです:

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と思われます。それに対処する最善の方法は何ですか?比較のために

thisが正常に動作web site 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)))) 
    } 
} 

答えて

3

私はこれを考え出したと思います。これは主にElのby:iter.nextを再計算するby nameパラメータを使用しているように思えました。また、最初に2つの異なるpeek(iter).runで計算を誤って呼び出す方法もありました。私が最初にヴァルiter.nextを割り当てるために列挙子を書き直し(そしてまたプロセスにおける末尾再帰製):次に

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))) 
    } 
} 

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 

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 

はこれを返します

0

あなたはサイズ1の使い捨てイテレータを作成することにより、副作用を回避することができます

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)))) 
} 
+0

最初はうまくいきましたが、イテレータは実際にはdef firstTwo [E]:IterV [E、(Option [E]、Option [E])] = for(a < - head ; b < - head)yield(a、b) 'returns'(Some(1)、Some(1)) ' – huynhjl

2

あなたは副作用を引き起こすiter.nextについて正しいです。私は、ストリームとイテレータの違いは何かという疑問が残ると思います。 This questionに関連情報があります。

2

イテレータは怠惰です。副作用(イテレータ)と怠惰は混在しません。たぶんこれは正しいことをするでしょう:

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のソースだけが知っているでしょう。副作用はそうです。