2011-07-26 32 views
5

Có cách nào nhanh chóng để sử dụng làm chức năng cụ thể (loại, giả sử, (A) => B) làm PartialFunction[A, B]? Cú pháp ngắn gọn nhất mà tôi biết là:Scala PartialFunctions từ bê tông

(a: A) => a match { case obj => func(obj) } 

Có một chuyển đổi ngầm bất cứ nơi nào, một cái gì đó như:

implicit def funcAsPartial[A, B](func: A => B) = new PartialFunction[A, B] { 

    def isDefinedAt(a: A) = true 
    def apply(a: A) = func(a) 

} 

Tôi đoán tôi chỉ viết những gì tôi đang tìm kiếm, nhưng điều này đã tồn tại trong thư viện Scala?

Trả lời

5

Thực hiện việc này với chuyển đổi ẩn là nguy hiểm, vì lý do tương tự mà (A) => B không được kế thừa từ PartialFunction[A, B]. Tức là, hợp đồng của PartialFunction đảm bảo rằng bạn có thể an toàn * gọi apply bất cứ nơi nào isDefinedAt trả về true. Hợp đồng của Function1 không bảo đảm như vậy.

Chuyển đổi tiềm ẩn của bạn sẽ dẫn đến một phần chức năng vi phạm hợp đồng của nó nếu bạn áp dụng nó cho một hàm không được xác định ở mọi nơi. Thay vào đó, hãy sử dụng pimp để thực hiện chuyển đổi rõ ràng:

implicit def funcAsPartial[A, B](f: A => B) = new { 
    /** only use if `f` is defined everywhere */ 
    def asPartial(): PartialFunction[A, B] = { 
     case a => f(a) 
    } 

    def asPartial(isDefinedAt: A => Boolean): PartialFunction[A, B] = { 
     case a if isDefinedAt(a) => f(a) 
    } 
} 

// now you can write 
val f = (i: Int) => i * i 

val p = f.asPartial // defined on all integers 
val p2 = f.asPartial(_ > 0) // defined only on positive integers 

* Như đã thảo luận trong nhận xét, có thể không hoàn toàn rõ ràng "an toàn" có nghĩa là gì ở đây. Cách tôi nghĩ về nó là một PartialFunction tuyên bố rõ ràng tên miền của nó theo nghĩa chính xác sau: nếu isDefinedAt trả về true cho một giá trị x, thì apply(x) có thể được đánh giá theo cách phù hợp với ý định của tác giả hàm. Điều đó không ngụ ý rằng apply(x) sẽ không ném ngoại lệ, nhưng chỉ đơn thuần là ngoại lệ là một phần của thiết kế của hàm (và phải được ghi lại).

+0

Cảm ơn bạn; Tôi đã có quan niệm sai rằng Function1 ngụ ý được xác định trên toàn bộ miền. –

+0

@AaronNovstrup: giải thích của bạn về hợp đồng của PartialFunction là hợp đồng duy nhất có ý nghĩa, nhưng không được phản ánh bởi ScalaDocs (ít nhất là cho đến 2.9.1). ScalaDocs của 'PartialFunction' cho rằng:" Một phần chức năng của kiểu 'PartialFunction [A, B]' là một hàm đơn nhất trong đó miền không nhất thiết phải bao gồm tất cả các giá trị của kiểu 'A'." Hơn nữa, họ không bao giờ cho rằng nó an toàn (theo nghĩa nào) để gọi f ở bất cứ nơi nào được định nghĩa, và điều đó khá dễ vi phạm, như được thực hiện bởi '' PartialFunction' literal '{case 0 => 1/0}'. Bạn lấy thông tin đó ở đâu? Báo cáo lỗi có cần phải được nộp không? – Blaisorblade

+0

@Blaisorblade Tôi tin rằng tôi đã đọc giải thích này trên danh sách gửi thư khi tôi đang học Scala (đã lâu rồi), và tôi không xem bất kỳ tài liệu nào khi tôi viết câu trả lời này. Và, vâng, thật dễ dàng và thậm chí hơi phổ biến để vi phạm hợp đồng này (ví dụ: để quấn/trả lại một ngoại lệ trong khối bắt). Điểm thực là PartialFunctions xác định miền của chúng trong khi các hàm bình thường không (với một số mờ về những gì thực sự có ý nghĩa). –

0

Không, tôi đã cố gắng tìm một vài tháng trước và kết thúc bằng văn bản của riêng tôi về cơ bản giống như của bạn.

+0

Dường như với tôi rằng '(A) => B' nên kế thừa từ' PartialFunction [A, B] ', không phải là cách khác. –

+1

Tôi sẽ đồng ý với điều đó, trên mặt đất là một (tổng) Chức năng là một phần chức năng mà xảy ra được định nghĩa ở khắp mọi nơi (isDefinedAt (x) = true). Tuy nhiên, Martin Odersky nói rằng một chức năng không được đảm bảo là một chức năng tổng thể, nó chỉ là tên miền của nó là không có giấy tờ. Vì vậy, một PartialFunction là một chức năng mà tài liệu tên miền của nó. –

+0

http://www.scala-lang.org/node/2750 –

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