2011-01-10 29 views
7

Tôi đang cố viết thư viện đo lường hiệu suất cho Scala. Ý tưởng của tôi là để minh bạch 'đánh dấu' phần để thời gian thực hiện có thể được thu thập. Thật không may tôi đã không thể uốn cong trình biên dịch theo ý muốn của tôi.Làm cách nào để tạo một hàm một phần với Generics trong Scala?

Một ví dụ phải thừa nhận là giả tạo về những gì tôi có trong tâm trí:

// generate a timing function 
val myTimer = mkTimer('myTimer) 

// see how the timing function returns the right type depending on the 
// type of the function it is passed to it 
val act = actor { 
    loop { 
     receive { 

      case 'Int => 
       val calc = myTimer { (1 to 100000).sum } 
       val result = calc + 10 // calc must be Int 
       self reply (result) 

      case 'String => 
       val calc = myTimer { (1 to 100000).mkString } 
       val result = calc + " String" // calc must be String 
       self reply (result) 
} 

Bây giờ, đây là xa nhất tôi nhận:

trait Timing { 
    def time[T <: Any](name: Symbol)(op: => T) :T = { 
     val start = System.nanoTime 
     val result = op 
     val elapsed = System.nanoTime - start 
     println(name + ": " + elapsed) 
     result 
    } 

    def mkTimer[T <: Any](name: Symbol) : (() => T) =>() => T = { 
     type c =() => T 
     time(name)(_ : c) 
    } 
} 

Sử dụng time chức năng trực tiếp làm việc và trình biên dịch sử dụng một cách chính xác loại trả về của hàm ẩn danh để nhập hàm 'thời gian':

val bigString = time('timerBigString) { 
    (1 to 100000).mkString("-") 
} 
println (bigString) 

lớn như nó có vẻ, mô hình này có một số thiếu sót:

  • buộc người sử dụng để tái sử dụng các biểu tượng cùng một lúc mỗi lời gọi
  • làm cho nó khó khăn hơn để làm công cụ tiên tiến hơn như giờ dự án cấp được xác định trước
  • không cho phép thư viện để khởi tạo một lần một cấu trúc dữ liệu cho 'timerBigString

vì vậy, ở đây nói mkTimer, mà sẽ cho phép tôi để áp dụng một phần chức năng thời gian và tái sử dụng nó. Tôi sử dụng mkTimer như thế này:

val myTimer = mkTimer('aTimer) 
val myString= myTimer { 
    (1 to 100000).mkString("-") 
} 
println (myString) 

Nhưng tôi nhận được một lỗi biên dịch:

error: type mismatch; 
found : String 
required:() => Nothing 
(1 to 100000).mkString("-") 

tôi nhận được lỗi tương tự nếu tôi inline currying:

val timerBigString = time('timerBigString) _ 
val bigString = timerBigString { 
    (1 to 100000).mkString("-") 
} 
println (bigString) 

này hoạt động nếu tôi làm val timerBigString = time('timerBigString) (_: String), nhưng đây không phải là những gì tôi muốn. Tôi muốn trì hoãn việc nhập chức năng được áp dụng một phần cho đến khi ứng dụng.

Tôi kết luận rằng trình biên dịch quyết định kiểu trả về của hàm một phần khi tôi tạo lần đầu tiên, chọn "Không có gì" vì nó không thể đưa ra lựa chọn sáng suốt hơn.

Vì vậy, tôi đoán những gì tôi đang tìm kiếm là một loại kết buộc muộn của hàm được áp dụng một phần. Có cách nào để làm điều này không? Hoặc có thể có một con đường hoàn toàn khác mà tôi có thể theo dõi?

Vâng, cảm ơn vì đã đọc đến đây

-teo

Trả lời

7

Các mô hình thông thường khi bạn muốn Generics "lười biếng" là sử dụng một lớp học với một phương pháp áp dụng

class Timer(name: Symbol) { 
    def apply[T](op: => T) = time(name)(op) 
} 
def mkTimer(name: Symbol) = new Timer(name) 
+0

điểm trên! cảm ơn. –

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