2015-10-12 19 views
5

I thought Tôi cần tham số hóa chức năng của mình trên tất cả các loại Ordering[_]. Nhưng điều đó không hiệu quả.Làm thế nào để xác định một chức năng như chung chung trên tất cả các số trong scala?

Làm cách nào để làm cho chức năng sau hoạt động cho tất cả các loại hỗ trợ các hoạt động toán học bắt buộc và làm cách nào để tôi tự phát hiện ra?

/** 
    * Given a list of positive values and a candidate value, round the candidate value 
    * to the nearest value in the list of buckets. 
    * 
    * @param buckets 
    * @param candidate 
    * @return 
    */ 
    def bucketise(buckets: Seq[Int], candidate: Int): Int = { 

    // x <= y 
    buckets.foldLeft(buckets.head) { (x, y) => 
     val midPoint = (x + y)/2f 

     if (candidate < midPoint) x else y 
    } 
    } 

tôi đã cố gắng lệnh nhấp vào các nhà khai thác toán học (/, +) trong IntelliJ, nhưng chỉ nhận được một thông báo Sc synthetic function.

Trả lời

9

Nếu bạn chỉ muốn sử dụng thư viện chuẩn scala, hãy xem Numeric[T]. Trong trường hợp của bạn, vì bạn muốn làm một bộ phận không phải số nguyên, bạn sẽ phải sử dụng lớp con Fractional[T] của Numeric.

Dưới đây là cách mã sẽ xem xét bằng cách sử dụng thư viện chuẩn scala chuẩn. Lưu ý rằng Fractional kéo dài từ Ordered. Điều này thuận tiện trong trường hợp này, nhưng nó cũng không phải là toán học chung chung. Ví dụ. bạn không thể xác định Fractional[T] cho Complex vì nó không được đặt hàng.

def bucketiseScala[T: Fractional](buckets: Seq[T], candidate: T): T = { 
    // so we can use integral operators such as + and/
    import Fractional.Implicits._ 
    // so we can use ordering operators such as <. We do have a Ordering[T] 
    // typeclass instance because Fractional extends Ordered 
    import Ordering.Implicits._ 
    // integral does not provide a simple way to create an integral from an 
    // integer, so this ugly hack 
    val two = (implicitly[Fractional[T]].one + implicitly[Fractional[T]].one) 
    buckets.foldLeft(buckets.head) { (x, y) => 
    val midPoint = (x + y)/two 
    if (candidate < midPoint) x else y 
    } 
} 

Tuy nhiên, để tính toán số học chung chung tôi khuyên bạn nên xem spire. Nó cung cấp một hệ thống phân cấp phức tạp hơn nhiều về typeclasses số. Spire typeclasses cũng là chuyên ngành và do đó thường nhanh như làm việc trực tiếp với nguyên thủy.

Dưới đây là làm thế nào để sử dụng ví dụ sẽ tìm bằng chóp:

// imports all operator syntax as well as standard typeclass instances 
import spire.implicits._ 
// we need to provide Order explicitly, since not all fields have an order. 
// E.g. you can define a Field[Complex] even though complex numbers do not 
// have an order. 
def bucketiseSpire[T: Field: Order](buckets: Seq[T], candidate: T): T = { 
    // spire provides a way to get the typeclass instance using the type 
    // (standard practice in all libraries that use typeclasses extensively) 
    // the line below is equivalent to implicitly[Field[T]].fromInt(2) 
    // it also provides a simple way to convert from an integer 
    // operators are all enabled using the spire.implicits._ import 
    val two = Field[T].fromInt(2) 
    buckets.foldLeft(buckets.head) { (x, y) => 
    val midPoint = (x + y)/two 
    if (candidate < midPoint) x else y 
    } 
} 

Spire thậm chí cung cấp chuyển đổi tự động từ các số nguyên để T nếu tồn tại một Field[T], vì vậy bạn thậm chí có thể viết ví dụ như thế này (gần giống như phiên bản không chung chung). Tuy nhiên, tôi nghĩ ví dụ trên dễ hiểu hơn.

// this is how it would look when using all advanced features of spire 
def bucketiseSpireShort[T: Field: Order](buckets: Seq[T], candidate: T): T = { 
    buckets.foldLeft(buckets.head) { (x, y) => 
    val midPoint = (x + y)/2 
    if (candidate < midPoint) x else y 
    } 
} 

Cập nhật: chóp rất mạnh mẽ và chung chung, nhưng cũng có thể hơi khó hiểu đối với người mới bắt đầu. Đặc biệt là khi mọi thứ không hoạt động. Đây là một số excellent blog post giải thích cách tiếp cận cơ bản và một số vấn đề.

+0

OK, tôi sẽ kiểm tra chóp. Vấn đề là các tài liệu scala cho Int (http://www.scala-lang.org/api/current/index.html#scala.Int) không liệt kê các đặc điểm mà nó mở rộng để tôi kết thúc việc đoán về '. Làm thế nào tôi có thể tìm ra những đặc điểm 'Int' mở rộng để tôi có thể tìm thấy' Numeric [T] 'cho bản thân mình? – jbrown

+0

@jbrown Đặt hàng là [typeclass] (http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html). Typeclasses không hoạt động khi sử dụng thừa kế. –

+0

Vậy làm thế nào có thể biết được, bằng cách xem các tài liệu, mà typeclasses áp dụng cho Int? – jbrown

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