2010-04-24 31 views
8

Tôi đang viết trình tạo mã tạo đầu ra Scala.Làm thế nào để xác định toán tử bậc ba trong Scala giữ lại mã thông báo hàng đầu?

Tôi cần mô phỏng toán tử bậc ba theo cách mà các thẻ dẫn đến '?' vẫn còn nguyên vẹn.

ví dụ: chuyển đổi biểu thức c ? p : q thành c something. Đơn giản if(c) p else q không đạt tiêu chí của tôi, vì nó yêu cầu đặt if( trước c.

nỗ lực đầu tiên của tôi (vẫn còn sử dụng c/p/q như trên) được

 
c match { case(true) => p; case _ => q } 

một lựa chọn Tôi tìm thấy là:

 
class ternary(val g: Boolean => Any) { def |: (b:Boolean) = g(b) } 

implicit def autoTernary (g: Boolean => Any): ternary = new ternary(g) 

cho phép tôi viết:

 
c |: { b: Boolean => if(b) p else q } 

Tôi thích giao diện tổng thể của tùy chọn thứ hai, nhưng có cách nào làm cho nó ít tiết hơn không?

Cảm ơn

+0

ví dụ: một cái gì đó bằng cách sử dụng '_' thay cho b: Boolean sẽ được tốt đẹp, nhưng tôi không thể có được bất cứ điều gì để làm việc ngay –

+1

Xem 'BooleanW #?' từ Scalaz: http://scalaz.googlecode.com/svn/continuous/latest /browse.sxr/scalaz/BooleanW.scala.html – retronym

Trả lời

14

Mặc dù cú pháp không đánh giá theo thứ tự dự kiến ​​- nó liên kết với các điều kiện để lựa chọn đầu tiên - bạn có thể làm điều hành ternary riêng của bạn như thế này:!

class IfTrue[A](b: => Boolean, t: => A) { def |(f: => A) = if (b) t else f } 
class MakeIfTrue(b: => Boolean) { def ?[A](t: => A) = new IfTrue[A](b,t) } 
implicit def autoMakeIfTrue(b: => Boolean) = new MakeIfTrue(b) 

Bí quyết là giải thích ? làm phương pháp trên đối tượng MakeIfTrue liên kết điều kiện với đối tượng để trả lại trong trường hợp "đúng". Đối tượng IfTrue kết quả hiện đang sử dụng phương thức | làm yêu cầu đánh giá điều kiện, trả về tùy chọn đúng được lưu trữ nếu điều kiện là đúng hoặc chỉ được truyền vào nếu nó sai.

Lưu ý rằng tôi đã sử dụng các công cụ như => A thay vì chỉ A - thông số tên - để không đánh giá biểu thức trừ khi nó thực sự được sử dụng. Vì vậy, bạn sẽ chỉ đánh giá bên mà bạn thực sự cần (giống như một tuyên bố nếu).

Hãy xem nó trong hành động:

scala> List(1,3,2).isEmpty ? "Empty" | "Nonempty" 
res0: java.lang.String = Nonempty 

scala> (4*4 > 14) ? true | false 
res1: Boolean = true 

scala> class Scream(s: String) { println(s.toUpperCase + "!!!!") } 
defined class Scream 

scala> true ? new Scream("true") | new Scream("false") 
TRUE!!!! 
res3: Scream = [email protected] 

(PS Để tránh nhầm lẫn với các thư viện diễn viên ?, có thể bạn nên gọi nó là cái gì khác như |?.)

+0

Doh, quá chậm. Tôi đang trong tiến trình gõ một cái gì đó tương tự như này lên, chỉ để có được "2 câu trả lời mới" sợ hãi tin nhắn –

+0

@ Jackson: lựa chọn thay thế thú vị vẫn còn đáng giá! –

+0

Đẹp! Điều duy nhất tôi sẽ thay đổi là? đến |? để có được ưu tiên nhà điều hành thấp nhất. –

4

Bạn có thể sử dụng một cái gì đó như thế này

sealed trait TernaryOperand[A] { 
    def >(q: => A): A 
} 

case class TernarySecond[A](val p: A) extends TernaryOperand[A] { 
    def >(q: => A) = p 
} 

case class TernaryThird[A]() extends TernaryOperand[A] { 
    def >(q: => A) = q 
} 

implicit def ternary(c: Boolean) = new { 
    def ?[A](p: => A): TernaryOperand[A] = if (c) TernarySecond(p) else TernaryThird() 
} 

val s1 = true ? "a" > "b" 
println(s1) //will print "a" 

val s2 = false ? "a" > "b" 
println(s2) //will print "b" 

Mã này chuyển đổi bất kỳ giá trị boolean thành kiểu ẩn danh có phương thức được gọi là ?. Tùy thuộc vào giá trị của boolean, phương thức này sẽ trả về TernarySecond hoặc TernaryThird. Cả hai đều có một phương thức gọi là > trả về toán hạng thứ hai hoặc thứ ba tương ứng.

14

Hãy giữ nó đơn giản:

Java:

tmp = (a > b) ? a : b; 

Scala:

tmp = if (a > b) a else b 

Bên cạnh sự đơn giản, rõ ràng và nhanh chóng vì: không phân bổ đối tượng bạn không cần , giữ cho bộ thu gom rác ra khỏi phương trình (vì nó luôn luôn như vậy) và sử dụng bộ nhớ cache của bộ xử lý tốt hơn.

+1

Đây là câu trả lời yêu thích của tôi. Lời giải thích của bạn đơn giản như giải pháp. – theJollySin

+2

Điều này giải quyết một vấn đề khác, không phải vấn đề được nêu trong câu hỏi. –

0

hành ternary mà thêm sự cải thiện của tôi với tất cả sự triển khai Michel Kramer của và Rex Kerr:

  • cải thiện của tôi để sử dụng lớp giá trị mới Scala để tránh đấm bốc trên đầu.
  • Gọi bằng tên trên các toán hạng thứ 2 và thứ 3 để chỉ toán hạng được chọn được đánh giá.
  • Giá trị cuộc gọi của Michel trên toán hạng đầu tiên (Boolean) để tránh chi phí trên tên; nó luôn được đánh giá.
  • Lớp bê tông của Rex cho điều kiện để tránh mọi chi phí cho lớp ẩn danh.
  • Đánh giá của Michel về điều kiện để xác định lớp nào cần xây dựng để tránh chi phí của một hàm tạo hai đối số.

.

sealed trait TernaryResult[T] extends Any { 
    def |(op3: => T): T 
} 

class Ternary2ndOperand[T](val op2: T) extends AnyVal with TernaryResult[T] { 
    def |(op3: => T) = op2 
} 

class Ternary3rdOperand[T](val op2: T) extends AnyVal with TernaryResult[T] { 
    def |(op3: => T) = op3 
} 

class Ternary(val op1:Boolean) extends AnyVal { 
    def ?[A](op2: => A): TernaryResult[A] = if (op1) new Ternary2ndOperand(op2) else new Ternary3rdOperand(op2) 
} 

object Ternary { 
    implicit def toTernary(condition: Boolean) = new Ternary(condition) 
} 

Lưu ý cải thiện hơn if else không chỉ là 6 ký tự được lưu. Với màu cú pháp của Scala IDE trên các từ khóa giống nhau (ví dụ như màu tía) cho if, else, nulltrue, có độ tương phản tốt hơn trong một số trường hợp (không được hiển thị bằng màu cú pháp bên dưới như được hiển thị trên trang web này):

if (cond) true else null 
cond ? true | null 
Các vấn đề liên quan