2016-02-22 16 views
9

f:() => Option[T] bir yan etki "üretici" işlevine sahip olduğumuzu varsayalım. Bu, Some'u sürekli olarak None döndürecek bir sonraki noktaya kadar tekrar tekrar çağrıldığında döndürür. (ör. EOF'de null üreten sarılı bir Java API'si bu tür bir davranışa sahip olabilir).Seçeneği bir Yineleyici'ye döndüren bir yan etkili işlevi döndürün

  • Standart Scala kütüphane yapılar tercih
  • dizisi keyfi uzun olabilir
  • ve holding tüm değerleri:

    aşağıdaki kısıtlamalar ile, bir TraversableOnce veya Iterator gibi bir şey bu işlevi kaydırmak için mümkün mü , Örneğin Bir Stream içinde
  • Benzer
  • görünür kullanıcı kaynak kodu

bazı yararlı yöntemler vardır bir var

  • Konu güvenliği gerekli değildir kullanmamalısınız yığın taşması olasılığı yoktur olmalıdır istenmediği Iterator nesnesinde, ancak kullanım durumumla tam olarak eşleşen hiçbir şey yok. Herhangi bir fikir karşılama!

  • cevap

    6

    Bu hile yapar:

    def wrap[T](f:() => Option[T]): Iterator[T] = { 
        Iterator.continually(f()).takeWhile(_.isDefined).flatten  
    } 
    

    REPL testi:

    scala> :paste 
    // Entering paste mode (ctrl-D to finish) 
    var i = 0 
    def sideEffectingFunc(): Option[Int] = { 
        i += 1 
        if (i < 10) Some(i) 
        else None 
    } 
    // Exiting paste mode, now interpreting. 
    
    i: Int = 0 
    sideEffectingFunc:()Option[Int] 
    
    scala> val it = wrap(sideEffectingFunc) 
    it: Iterator[Int] = non-empty iterator 
    
    scala> it.toList 
    res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9) 
    
    +0

    Mükemmel ve hızlı yanıt için çok teşekkürler! – satyagraha

    +0

    Son '.map (_. Get)', Scala'nın son sürümlerinde, örtülü bir TraversableOnce CBF ve ilişkili yineleyici içeren ".flatten" ile değiştirilebilir. Bunun hala kriterleri karşıladığını düşünüyorum. – satyagraha

    +0

    Haklısınız. Bunu özledim çünkü “yineleyici” nin scaladoku bundan bahsetmiyor. Bir scaladoc böcek gibi görünüyor: 'flatten' zenginleştirici sınıf 'TraversableOnce.FlattenOps' gelir ve zenginleştirmeler scaladoc (ve çoğu) tarafından ele alınması gerekiyor. Cevabımı güncelledim. –

    2

    Biraz dik, bu davranış sağlanabilir kullanarak eşyordamlar. coroutines sağlayan Scala için en az bir kütüphane bulunmaktadır, buradan bulabilirsiniz: alternatif olarak

    import org.coroutines._ 
    
    def sideEffectingFunction = coroutine {() => 
        val limit = new scala.util.Random().nextInt(10) 
        val seq = new scala.util.Random 
        var counter = 0 // mutable state is preserved between coroutine invocations 
        while (counter < limit) { 
        counter += 1 
        yieldval(seq.nextInt) 
        } 
    } 
    defined function sideEffectingFunction 
    
    @ val cr = call(sideEffectingFunction()) 
    cr: Coroutine.Frame[Int, Unit] = Coroutine.Frame<depth: 1, live: true> 
    @ cr.resume 
    res31: Boolean = true 
    @ cr.value 
    res32: Int = 57369026 
    @ cr.resume 
    res33: Boolean = true 
    @ cr.value 
    res34: Int = -1226825365 
    @ cr.resume 
    res35: Boolean = true 
    @ cr.value 
    res36: Int = 1304491970 
    @ cr.resume 
    res37: Boolean = false 
    @ cr.value 
    java.lang.RuntimeException: Coroutine has no value, because it did not yield. 
        scala.sys.package$.error(package.scala:27) 
        org.coroutines.Coroutine$Frame$mcI$sp.value$mcI$sp(Coroutine.scala:130) 
        cmd38$.<init>(Main.scala:196) 
        cmd38$.<clinit>(Main.scala:-1) 
    

    Veya: Burada

    http://storm-enroute.com/coroutines/ sen istediğini elde etmek yazacağım kod örneği verilmiştir:

    @ val cr = call(sideEffectingFunction()) 
    cr: Coroutine.Frame[Int, Unit] = Coroutine.Frame<depth: 1, live: true> 
    @ cr.resume 
    res60: Boolean = true 
    @ val iter = Iterator.continually(cr.value).takeWhile(_ => cr.resume) 
    iter: Iterator[Int] = non-empty iterator 
    @ iter.foreach(println) 
    1595200585 
    995591197 
    -433181225 
    220387254 
    201795229 
    754208294 
    -363238006 
    

    T: bir önceki cevabın ruhu içinde

    @ val cr = call(sideEffectingFunction()) 
    cr: Coroutine.Frame[Int, Unit] = Coroutine.Frame<depth: 1, live: true> 
    @ while(cr.resume) println(cr.value) 
    -1888916682 
    1135466162 
    243385373 
    

    Veya, Coroutines yaklaşımının avantajı, her ikisi de dış dünyadan bir koroutinin içinde gizlenmiş olan, altta yatan yan etki fonksiyonlarının çağrışımları arasında değişmez bir durumun kalmasıdır. Koroutinler de oluşturulabilir ve birbirlerini çağırırlar.

    Tabii ki, koroutinler, görevinizin yerine getirilmesinden çok daha fazla güç verir, bu nedenle bunları eklemek için fazladan bir ihtiyaç olabilir. Ancak, farkında olmak için kullanışlı bir teknik.

    İlgili konular