سؤال

كيف يمكن أن ينفذ واحد C # yield return باستخدام مستمرات scala؟ أود أن أكون قادرا على كتابة Scala IteratorS في نفس النمط. طعنة في التعليقات على هذا آخر الأخبار scala, ، لكنه لا يعمل (حاول استخدام بيتا Scala 2.8.0). إجابات في سؤال ذي صلة أقترح أن هذا ممكن، ولكن على الرغم من أنني كنت ألعب مع استمرار محددة لفترة من الوقت، إلا أنني لا أستطيع أن ألتفها بالضبط رأسي حول كيفية القيام بذلك.

هل كانت مفيدة؟

المحلول

قبل أن نقدم استمرارنا، نحتاج إلى بناء بعض البنية التحتية. أدناه هو الترامبولين التي تعمل على Iteration أشياء. التكرار هو حساب يمكن إما Yield قيمة جديدة أو يمكن أن يكون Done.

sealed trait Iteration[+R]
case class Yield[+R](result: R, next: () => Iteration[R]) extends Iteration[R]
case object Done extends Iteration[Nothing]

def trampoline[R](body: => Iteration[R]): Iterator[R] = {
  def loop(thunk: () => Iteration[R]): Stream[R] = {
    thunk.apply match {
      case Yield(result, next) => Stream.cons(result, loop(next))
      case Done => Stream.empty
    }
  }
  loop(() => body).iterator
}

يستخدم الترامبولين حلقة داخلية تقوم بتحويل تسلسل Iteration الكائنات في أ Streamوبعد ثم نحصل على Iterator بالاتصال iterator على كائن دفق الناتج. باستخدام أ Stream تقييمنا كسول. نحن لا نقيم التكرار الخاص بنا حتى هناك حاجة.

يمكن استخدام الترامبولين لبناء جهاز استئناف مباشر.

val itr1 = trampoline {
  Yield(1, () => Yield(2, () => Yield(3, () => Done)))
}

for (i <- itr1) { println(i) }

هذا فظيع جدا للكتابة، لذلك دعونا نستخدم مستمرات محددة لإنشاء لدينا Iteration الكائنات تلقائيا.

نحن نستخدم ال shift و reset المشغلين لكسر الحساب IterationS، ثم استخدام trampoline لتحويل IterationS في Iterator.

import scala.continuations._
import scala.continuations.ControlContext.{shift,reset}

def iterator[R](body: => Unit @cps[Iteration[R],Iteration[R]]): Iterator[R] =
  trampoline {
    reset[Iteration[R],Iteration[R]] { body ; Done }
  }

def yld[R](result: R): Unit @cps[Iteration[R],Iteration[R]] =
  shift((k: Unit => Iteration[R]) => Yield(result, () => k(())))

الآن يمكننا إعادة كتابة مثالنا.

val itr2 = iterator[Int] {
  yld(1)
  yld(2)
  yld(3)
}

for (i <- itr2) { println(i) }

أفضل بكثير!

الآن هنا مثال من صفحة # المرجعية بالنسبة yield هذا يظهر بعض الاستخدام الأكثر تقدما. يمكن أن تكون الأنواع صعبة بعض الشيء للتعود عليها، ولكن كل ذلك يعمل.

def power(number: Int, exponent: Int): Iterator[Int] = iterator[Int] {
  def loop(result: Int, counter: Int): Unit @cps[Iteration[Int],Iteration[Int]] = {
    if (counter < exponent) {
      yld(result)
      loop(result * number, counter + 1)
    }
  }
  loop(number, 0)
}

for (i <- power(2, 8)) { println(i) }

نصائح أخرى

تمكنت من اكتشاف طريقة للقيام بذلك، بعد بضع ساعات أخرى من اللعب حولها. اعتقدت أن هذا كان أبسط لالتفاف رأسي حول جميع الحلول الأخرى التي رأيتها حتى الآن، على الرغم من أنني فعلت ذلك بعد ذلك كثيرا اميال' حلول.

def loopWhile(cond: =>Boolean)(body: =>(Unit @suspendable)): Unit @suspendable = {
  if (cond) {
    body
    loopWhile(cond)(body)
  }
}

  class Gen {
    var prodCont: Unit => Unit = { x: Unit => prod }
    var nextVal = 0
    def yld(i: Int) = shift { k: (Unit => Unit) => nextVal = i; prodCont = k }
    def next = { prodCont(); nextVal }
    def prod = {
      reset {
        // following is generator logic; can be refactored out generically
        var i = 0
        i += 1
        yld(i)
        i += 1
        yld(i)
        // scala continuations plugin can't handle while loops, so need own construct
        loopWhile (true) {
          i += 1
          yld(i)
        }
      }
    }
  }
  val it = new Gen
  println(it.next)
  println(it.next)
  println(it.next)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top