2010-10-31 24 views
12

Bu bir süredir merak ettiğim bir şey. #isDefinedAt değerlendirilmiştir desenler her ardından da #apply değerlendirilir, iki ayrı çağrıları içine bu kesiliyor olarakPartialFunction tasarımı verimsiz mi?

if (pf.isDefinedAt(in)) pf(in) 

: Bu desene görüyorum. Örneğin:

object Ex1 { 
    def unapply(in: Int) : Option[String] = { 
    println("Ex1") 
    if (in == 1) Some("1") else None 
    } 
} 

object Ex2 { 
    def unapply(in: Int) : Option[String] = { 
    println("Ex2") 
    if (in == 2) Some("2") else None 
    } 
} 

val pf : PartialFunction[Int,String] = { 
    case Ex1(result) => result 
    case Ex2(result) => result 
} 

val in = 2 

if (pf.isDefinedAt(in)) pf(in) 

bir PartialFunction çağrılırken

senin desen son maçları kötü durumda,
Ex1 
Ex2 
Ex1 
Ex2 
res52: Any = 2 

, iki kez sizin desenler/presi değerlendirdi ettik yazdırır hangisi. Bu, sadece basit bir sınıf veya liste deseni eşleştirmesi (örneğin, bir XML belgesini ayrıştırıp bir değer nesneleri döndürdüyseniz bir çıkarıcıya sahip olsaydınız) yapan özel çıkarıcılar üzerinde eşleşirken verimsiz hale gelebilir.

Kısmi İşlev # kaldırma sorunu aynı çift değerlendirme:

scala> pf.lift(2) 
Ex1 
Ex2 
Ex1 
Ex2 
res55: Option[String] = Some(2) 

potansiyel iki kere extractors tüm uğramadan tanımlanması durumunda koşullu bir işlevi çağırmak için bir yolu var mı?

cevap

15

Scala-iç yapıları posta listesi şimdi sağ a conversation going on about thisyoktur. Martin Odersky yeni bir tür önerdi: FunctionWithDefault. Martin sadece bir çalışma zamanı cezasının bahsediyor, ama PartialFunction kullanmanın (sınıf dosyası bloattan) bir derleme zamanı cezası:

İlk olarak, bir kez daha sonra uygulamak ve iki kez desen eşleştirme kodu oluşturmanız gerekir tekrar isDefinedAt. İkincisi, aynı zamanda, fonksiyonun uygulanabilir olup olmadığını test etmek ve daha sonra gerçekte uygulamak için, kodu iki kez tekrarlamamız gerekir.

Sorunuzun cevabı aslında değiştirmez (PartialFunction ait) "evet" ve bu davranış ya geriye doğru uyumluluk sorunları nedeniyle (örneğin, neyi isDefinedAt yan etkileyen ise).

yeni tip önerilmektedir, FunctionWithDefault bir isDefinedAt ve bir yöntemi vardır: biraz Option s getOrElse yöntem gibi çalışır

trait FunctionWithDefault[-I, +O] { 
    def applyOrElse[OO >: O](i : I, default : I => OO) : OO 
} 

.

Her zaman olduğu gibi, bu verimsizliğin, büyük bir çoğunluğun performansında her türlü performansın sorunu olduğunu hayal edemiyorum.

+0

Detaylı yanıt için teşekkür ederiz! FunctionWithDefault, aradığım şey gibi görünüyor. – Collin

+1

Performans eşleştirme kodunda karmaşık eşleşme ifadeleri varsa, iki kez desen eşleştirmesi kesinlikle büyük bir performans isabetidir! Ve eğer 'varsayılan' isim ile geçilirse, bunun bir seçenek döndürmekten daha verimli olması nasıl beklenir? Belki de scala-internals okumalıyım. –

+0

Varsayılan yanlışlık var, daha ziyade bir 'I => OO' –