2011-09-29 35 views
18

Given:Thứ tự và có thứ tự và so sánh lựa chọn

case class Person(name: String) 

và cố gắng để làm:

scala> List(Person("Tom"), Person("Bob")).sorted 

kết quả trong một đơn khiếu nại về việc thiếu Thứ tự.

<console>:8: error: could not find implicit value for parameter ord: Ordering[Person] 
    List(Person("Tom"), Person("Bob")).sorted 

Tuy nhiên điều này:

case class Person(name: String) extends Ordered[Person] { 
    def compare(that: Person) = this.name compare that.name } 

hoạt động tốt như mong đợi:

scala> List(Person("Tom"), Person("Bob")).sorted 
res12: List[Person] = List(Person(Bob), Person(Tom)) 

mặc dù không có đặt hàng hoặc implicits liên quan.

Câu hỏi # 1: điều gì đang xảy ra ở đây? (Tiền của tôi là về cái gì ngầm ...)

Tuy nhiên, do ở trên và thực tế rằng đây:

scala> Person("Tom") > Person("Bob") 
res15: Boolean = true 

công trình, và đó cũng này:

scala> List(Some(2), None, Some(1)).sorted 

công trình ra khỏi hộp:

res13: List[Option[Int]] = List(None, Some(1), Some(2)) 

tôi sẽ hy vọng điều này:

scala> Some(2) > Some(1) 

cũng sẽ làm việc, tuy nhiên nó không:

<console>:6: error: value > is not a member of Some[Int] 
     Some(2) > Some(1) 

Câu hỏi # 2: tại sao không, và làm thế nào tôi có thể lấy nó để làm việc?

Trả lời

9

Về câu hỏi đầu tiên của bạn: Ordered[T] kéo dài Comparable[T].Các đối tượng đồng Ordering cung cấp một tiềm ẩn Ordering[T] đối với bất kỳ giá trị mà có thể được chuyển đổi thành một Comparable[T]:

implicit def ordered[A <% Comparable[A]]: Ordering[A] 

Không có chuyển đổi ngầm A : Ordering => Ordered[A] - đó là lý do tại sao Some(1) > Some(2) sẽ không hoạt động. Sẽ rất có vấn đề nếu bạn nên xác định một chuyển đổi như vậy khi bạn có thể kết thúc các đối tượng của mình thành Ordered trường hợp và sau đó tạo một Ordering của nó một lần nữa (v.v ...). Thậm chí tệ hơn: bạn có thể tạo hai trường hợp Ordered với các trường hợp khác nhau Ordering trong phạm vi mà tất nhiên không phải là những gì bạn muốn.

2

Định nghĩa của phương pháp sorted Danh sách là:

def sorted [B >: A] (implicit ord: Ordering[B]): List[A] 

Vì vậy, có, mọi thứ tiềm ẩn đang xảy ra, nhưng nhiều lớp trong thư viện chuẩn có các đối tượng tiềm ẩn gắn liền với họ mà không cần phải nhập khẩu đầu tiên.

Đối tượng đồng hành Ordering xác định một loạt các thứ tự ngầm định. Trong số này có một OptionOrdering và IntOrdering, giúp giải thích khả năng của một danh sách để gọi sorted.

Để đạt được khả năng sử dụng các nhà khai thác khi có một chuyển đổi ngầm có sẵn, bạn cần phải nhập khẩu đối tượng đó, ví dụ:

def cmpSome(l:Option[Int], r:Option[Int])(implicit ord:Ordering[Option[Int]]) = { 
    import ord._ 
    l < r 
} 

scala> cmpSome(Some(0), Some(1)) 
res2: Boolean = true 
+0

Điều đó không thực sự trả lời câu hỏi tại sao việc triển khai Ordered [T] kỳ diệu mang lại một trường hợp Ordering [T]. Và tại sao bạn phải tạo một phương pháp để thực hiện so sánh cuối cùng? –

+0

Tôi đã thực hiện phương pháp để tôi có thể truy cập vào phiên bản Ordering. Tôi nhập nội dung của cá thể đó để tôi có thể chuyển đổi ẩn của nó thành 'Ops', xác định một số toán tử so sánh. Sử dụng cùng phương thức đó, cuối cùng tôi đã tìm ra chính xác nơi chuyển đổi ngầm cho một 'Ordered' là gì. http://www.scala-lang.org/api/current/index.html#scala.math.LowPriorityOrderingImplicits – Dylan

+0

Nhưng điều đó có vẻ khá nhiều công việc chỉ để có thể so sánh hai Tùy chọn? –

23

Nếu bạn cài đặt implicits hơi-quá-huyền diệu-cho-mặc-phạm vi tiền thưởng, bạn có thể so sánh các tùy chọn như vậy:

scala> import scala.math.Ordering.Implicits._ 
import scala.math.Ordering.Implicits._ 

scala> def cmpSome[T: Ordering](x: Option[T], y: Option[T]) = x < y 
cmpSome: [T](x: Option[T], y: Option[T])(implicit evidence$1: Ordering[T])Boolean 

Việc nhập khẩu cung cấp cho bạn một tiềm ẩn từ một Thứ tự đến lớp với hoạt động infix, do đó, nó đủ để có thứ tự mà không cần nhập khẩu khác.

+0

Tốt hơn ... nhưng vẫn còn rất nhiều công việc, theo ý kiến ​​của tôi có lẽ không quá khiêm tốn. :) Tôi hiểu rằng có thể có lý do tại sao nó theo cách này, nhưng từ quan điểm của người dùng, nó có vẻ hợp lý khi bạn có thể so sánh hai tùy chọn mà không có bất kỳ fuzz nào mà bạn có thể * sắp xếp * một danh sách của chúng mà không có bất kỳ lông tơ nào. .. kể từ khi bạn phải so sánh trong khác để sắp xếp, phải không? –

+0

Bạn có thể sắp xếp chúng bởi vì bạn gọi một phương thức có thứ tự ngầm định. Ở đây bạn đang viết một phương pháp mà có một thứ tự ngầm định. Một nơi nào đó, một thứ tự phải nhập hình ảnh, bởi vì Tùy chọn [T] s không thể so sánh được. – extempore

0

Tôi giả sử bạn hiểu lý do tại sao được sắp xếp không hoạt động khi bạn không vượt qua trong Đặt hàng và không có quy tắc nào có sẵn trong phạm vi. Là lý do tại sao chức năng được sắp xếp hoạt động khi bạn mở rộng lớp học của bạn từ đặc điểm Ordered. Câu trả lời là khi bạn mở rộng từ đặc điểm Ordered, loại mã kiểm tra như các đặc điểm có chứa chức năng như <,> vv Vì vậy, không cần phải làm chuyển đổi tiềm ẩn và do đó không có phàn nàn về việc thiếu thứ tự ngầm.

Đối với câu hỏi thứ hai của bạn, Some(2) > Some(1) sẽ không làm việc vì một số không mở rộng các đặc điểm có thứ tự, cũng như thế dường như có bất kỳ chức năng tiềm ẩn trong phạm vi mà mặc nhiên chuyển đổi một Một số đến một cái gì đó có chức năng >

2

Để trả lời câu hỏi thứ hai của bạn, tại sao bạn không thể làm điều này: Some(2) > Some(1)

Bạn có thể nhập và làm việc với Option[Int] thay vì Some[Int].

@ import scala.math.Ordering.Implicits._ 
import scala.math.Ordering.Implicits._ 
@ Some(2) > Some(1) // doesn't work 
cmd11.sc:1: value > is not a member of Some[Int] 
val res11 = Some(2) > Some(1) 
        ^
Compilation Failed 
@ (Some(2): Option[Int]) > (Some(1): Option[Int]) // Option[Int] works fine 
res11: Boolean = true 
@ Option(2) > Option(1) 
res12: Boolean = true 
@ (None: Option[Int]) > (Some(1): Option[Int]) 
res13: Boolean = false 

Trên thực tế loại của bạn có thể sẽ được Option[Int] hơn Some[Int] vì vậy nó sẽ không được như vậy xấu xí và bạn sẽ không cần upcasting rõ ràng.

Các vấn đề liên quan