Üçlü Operatör Benzer?:


94

Bunun gibi yapılardan kaçınmaya çalışıyorum:

val result = this.getClass.getSimpleName
if (result.endsWith("$")) result.init else result

Tamam, bu örnekte thenve elsedalı basittir, ancak karmaşık olanları görüntüleyebilirsiniz. Aşağıdakileri oluşturdum:

object TernaryOp {
  class Ternary[T](t: T) {
    def is[R](bte: BranchThenElse[T,R]) = if (bte.branch(t)) bte.then(t) else bte.elze(t)
  }
  class Branch[T](branch: T => Boolean) {
    def ?[R] (then: T => R) = new BranchThen(branch,then)
  }
  class BranchThen[T,R](val branch: T => Boolean, val then: T => R)
  class Elze[T,R](elze: T => R) {
    def :: (bt: BranchThen[T,R]) = new BranchThenElse(bt.branch,bt.then,elze)
  }
  class BranchThenElse[T,R](val branch: T => Boolean, val then: T => R, val elze: T => R)
  implicit def any2Ternary[T](t: T) = new Ternary(t)
  implicit def fct2Branch[T](branch: T => Boolean) = new Branch(branch)
  implicit def fct2Elze[T,R](elze: T => R) = new Elze(elze)
}

Bunu tanımladığımda, yukarıdaki basit örneği şununla değiştirebilirim:

this.getClass.getSimpleName is {s: String => s.endsWith("$")} ? {s: String => s.init} :: {s: String => s}

Ama nasıl kurtulabilirim s: String =>? Bunun gibi bir şey istiyorum:

this.getClass.getSimpleName is {_.endsWith("$")} ? {_.init} :: {identity}

Sanırım derleyicinin türleri çıkarmak için fazladan malzemeye ihtiyacı var.


Cevabımda aslında buna sahip olmadığım için - sorun yaşamanızın nedeni, bu tür çıkarımının en iyi soldan sağa çalışmasıdır, ancak belirteçlerinizi operatör önceliği nedeniyle sağdan sola birleştiriyorsunuz. Tüm ifadelerinizi (aynı önceliğe sahip) oluşturur ve her şeyin gruplanma şeklini değiştirirseniz, istediğiniz çıkarımı elde edersiniz. (Eğer olurdu Yani HasIs, IsWithCondition, ConditionAndTrueCasesoldan sağa doğru ifade parçalarını oluşturmak istiyorum sınıfları.)
Rex Kerr

Bilinçsiz bir şekilde soldan sağa tür çıkarımının yolunu düşündüm, ancak özellikle ?yöntem adı olarak ilk karakter ve :sol ilişkilendirme için a olarak herhangi bir diğer alfanum karakterinden önce başlayarak, yöntem adlarının operatör önceliği ve ilişkilendirilebilirliği ile sıkışıp kaldım . Bu nedenle, soldan sağa doğru çalışan tür çıkarımlarını elde etmek için yeni yöntem adlarını yeniden düşünmem gerekiyor. Teşekkürler!
Peter Schmitz

Yanıtlar:


28

Biz birleştirebilirsiniz lider jetonları koruyan Scala'da bir üçlü operatörü nasıl tanımlanır? cevap ile bir değer iyi bir model sarma Is Seçeneği? almak

scala>   "Hi".getClass.getSimpleName |> {x => x.endsWith("$") ? x.init | x}
res0: String = String

scala> List.getClass.getSimpleName |> {x => x.endsWith("$") ? x.init | x}
res1: String = List

Bu ihtiyaçlarınız için yeterli mi?


Aklımdaki şeye çok yakın. güzel yaklaşım. Bunu düşüneceğim. İlk koddan kaçınmak için nedenim, valaşağıdaki bir ififadeye geçici olarak sahip olmamakla daha özlü olmaktı: Aklında olduğu gibi, tek satırda anlaşılır yapın.
Peter Schmitz

125

Gönderen Tony Morris'in Lambda Blog :

Bu soruyu çok duyuyorum. Evet öyle. Bunun yerine c ? p : qyazılırif(c) p else q .

Bu tercih edilmeyebilir. Belki Java ile aynı sözdizimini kullanarak yazmak istersiniz. Ne yazık ki yapamazsınız. Bunun nedeni :, geçerli bir tanımlayıcı olmamasıdır. Korkma, |öyle! Buna razı olur musun?

c ? p | q

O zaman aşağıdaki koda ihtiyacınız olacak. =>Bağımsız değişkenler üzerindeki ada göre çağrı ( ) ek açıklamalarına dikkat edin. Bu değerlendirme stratejisi, Java'nın üçlü operatörünü doğru şekilde yeniden yazmak için gereklidir. Bu Java'nın kendisinde yapılamaz.

case class Bool(b: Boolean) {   
  def ?[X](t: => X) = new {
    def |(f: => X) = if(b) t else f   
  } 
}

object Bool {   
  implicit def BooleanBool(b: Boolean) = Bool(b) 
}

İşte az önce tanımladığımız yeni operatörü kullanan bir örnek:

object T {   val condition = true

  import Bool._

  // yay!   
  val x = condition ? "yes" | "no"
}

İyi eğlenceler ;)


evet, bunu daha önce görmüştüm, ancak fark şu ki, a thenve elsecümlesinde bir argüman olarak ilk ifademin (değerlendirilmiş) değerini aldım .
Peter Schmitz

5
if(c) p else qYaklaşımı aldım ... diş tellerinin olmaması beni rahatsız ediyor ama bu sadece bir stil meselesi
rjohnston

17

Rex Kerr'in cevabı temel Scala'da ifade edildi:

"Hi".getClass.getSimpleName match {
  case x if x.endsWith("$") => x.init
  case x => x
}

eğer-else yapısının hangi bölümünü optimize etmek istediğinizden emin değilim.


çok düz yol. bazen günlük kullanım eşleşme / durum ifadelerini unutur. Ben sadece tek satırlık üçlü if then elsedeyime bağlı kaldım , ama bu gerçekten çözmenin anlaşılır bir yolu.
Peter Schmitz

1
Desen Eşleştirme, ikiden fazla dala kolaylıkla ölçeklenir.
Raphael


0

Çünkü: her zaman geri tiklerle kaçmadığınız sürece kendi başına geçerli bir operatör olmayacaktır :, başka bir karakterle gidebilirsiniz, örneğin "|" yukarıdaki cevaplardan birinde olduğu gibi. Ama keçi sakallı elvis nasıl olur?

implicit class Question[T](predicate: => Boolean) {
  def ?(left: => T) = predicate -> left
}
implicit class Colon[R](right: => R) {
  def ::[L <% R](pair: (Boolean, L)): R = if (q._1) q._2 else right
}
val x = (5 % 2 == 0) ? 5 :: 4.5

Elbette, eğer değerler listesiyse bu yine işe yaramayacaktır, çünkü kendilerinin :: operatörü vardır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.