SORU
15 EKİM 2012, PAZARTESİ


Bir erken iptal kat

Bir kat erken sonlandırmak için en iyi yolu nedir? Basitleştirilmiş bir örnek olarak, ** 5, sayıları toplamak istiyorum ama ben (tek sayı demek) sonlandırmak istiyor olabilirim beklemiyorum bir karşılaşma düşünün. Bu ilk bakışta

def sumEvenNumbers(nums: Iterable[Int]): Option[Int] = {
  nums.foldLeft (Some(0): Option[Int]) {
    case (Some(s), n) if n % 2 == 0 => Some(s   n)
    case _ => None
  }
}

Ancak, bu çözüm oldukça çirkin (eğer bir bilsem ., gibi.ve bir dönüş -- çok temiz ve net olurdu dosyalarda grup ve en kötüsü, eğer olmayan bir sayı bile karşılaşırsa bile tüm iterable erişir.

Ne erken sona erdirir yazmak için en iyi yol olurdu böyle kat? Sadece git ve bu yinelemeli olarak yazmak, ya da orada daha fazla kabul gören bir yol gerekir?

CEVAP
15 EKİM 2012, PAZARTESİ


İlk tercihim genellikle özyineleme kullanmak olacaktır. Sadece biraz daha az kompakt, potansiyel olarak daha hızlı (kesinlikle) yavaş ve erken sonlandırma mantığı daha açık ifade edebilir. Bu durumda garip olan iç içe defs gerekir:

def sumEvenNumbers(nums: Iterable[Int]) = {
  def sumEven(it: Iterator[Int], n: Int): Option[Int] = {
    if (it.hasNext) {
      val x = it.next
      if ((x % 2) == 0) sumEven(it, n x) else None
    }
    else Some(n)
  }
  sumEven(nums.iterator, 0)
}

Benim ikinci tercihim olurdu return gibi duruyor her şey sağlam ve sadece ihtiyacımız sarın kat def sana bir şey dönmek,--bu durum, zaten bir yöntem, böylece:

def sumEvenNumbers(nums: Iterable[Int]): Option[Int] = {
  Some(nums.foldLeft(0){ (n,x) =>
    if ((n % 2) != 0) return None
    n x
  })
}

bu durumda özyineleme iterable/yineleyici bir dönüşüm yapmak zorundaydık beri özyineleme ile özellikle şanssız var olsa da) çok daha kompakt. Sinirli denetim akışı her şeyin eşit olduğunda, önlemek için bir şey, ama burada değil. Değerli durumlarda kullanmaktan zarar gelmez.

Eğer ben bunu sık sık ve istediği içinde ortada bir yöntem bir yerde (yani yapamadım sadece dönüş), ben olsam muhtemelen kullanmak özel durum işleme oluşturmak için yerel olmayan bir kontrol akışı. İyi de, hata işleme ne yani, sonuçta, yararlı bir şey sadece zaman değil. Tek numara, izlemesi çok yavaş olan) yığın, ve bu hiç de kolay bir üretme NoStackTrace alt özellik ControlThrowable zaten bunu davranışıyla kaçınmaktır. Scala zaten bu dahili olarak kullanır (aslında, bu kapağı içeriden dönüş uygulayan nasıl!). Hadi biz de kendi (bir düzeltme olabilir ama iç içe değil):

import scala.util.control.ControlThrowable
case class Returned[A](value: A) extends ControlThrowable {}
def shortcut[A](a: => A) = try { a } catch { case Returned(v) => v }

def sumEvenNumbers(nums: Iterable[Int]) = shortcut{
  Option(nums.foldLeft(0){ (n,x) =>
    if ((x % 2) != 0) throw Returned(None)
    n x
  })
}

Elbette burada return kullanarak daha iyi, ama shortcut herhangi bir yerde, sadece koca bir yöntem kaydırmayı koyabilirsiniz unutmayın.

Benim için sırada yeniden hayata erken sonlandırma sinyali diye (ben ya da bir kütüphane bulmak için) kat olacaktır. Bunu yapmanın iki doğal yollardan ama None fesih ettiğinizi Option bir değer, değer değil yaymak; veya tamamlanma sinyalleri ikinci göstergesi fonksiyonu kullanmak için. Bu Scalaz kat Kim Stebel gösterdiği tembel zaten ilk durumda kapsar, ikinci (değişken bir uygulama ile) göstereyim:

def foldOrFail[A,B](it: Iterable[A])(zero: B)(fail: A => Boolean)(f: (B,A) => B): Option[B] = {
  val ii = it.iterator
  var b = zero
  while (ii.hasNext) {
    val x = ii.next
    if (fail(x)) return None
    b = f(b,x)
  }
  Some(b)
}

def sumEvenNumbers(nums: Iterable[Int]) = foldOrFail(nums)(0)(_ % 2 != 0)(_   _)

Sen özyineleme tarafından fesih uygulamak, iade edip, vs. tembellik. size kalmış.)

O ana uygun türevlerini kapsar bence; ayrıca başka bir seçenek vardır, ama bu durumda onları kullanmak istiyorsunuz neden emin değilim. (Iterator kendisini iyi işe yarasaydı findOrPrevious, ama değil, ve ekstra çalışma gerektirir bunu elle yapan bir aptal seçeneği kullanın.)

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • gsipek

    gsipek

    20 Temmuz 2007
  • PaulGBelliveau

    PaulGBellive

    5 Mart 2009
  • williamfitzsimmons

    williamfitzs

    14 Mart 2008