Sự khác biệt ngữ nghĩa đã được giải thích khá rõ trong the answer linked to by Plasty Grove.
Về mặt chức năng, có vẻ như không có sự khác biệt nhiều. Hãy xem xét một số ví dụ để xác minh điều đó. Đầu tiên, một chức năng bình thường:
scala> def modN(n: Int, x: Int) = ((x % n) == 0)
scala> modN(5, _ : Int)
res0: Int => Boolean = <function1>
Vì vậy, chúng ta có được một phần áp dụng <function1>
mà phải mất một Int
, bởi vì chúng tôi đã đưa nó trở thành số nguyên đầu tiên. Càng xa càng tốt. Bây giờ để tách lạng bộ:
scala> def modNCurried(n: Int)(x: Int) = ((x % n) == 0)
Với ký hiệu này, bạn muốn ngây thơ mong đợi sau đây để làm việc:
scala> modNCurried(5)
<console>:9: error: missing arguments for method modN;
follow this method with `_' if you want to treat it as a partially applied function
modNCurried(5)
Vì vậy, các nhiều tham số danh sách ký hiệu không thực sự dường như tạo một hàm cà ri ngay lập tức (giả sử tránh chi phí không cần thiết) nhưng chờ bạn nói rõ ràng rằng bạn muốn nó được thu lại (ký hiệu có một số số other advantages):
scala> modNCurried(5) _
res24: Int => Boolean = <function1>
Đó là chính xác cùng một điều chúng tôi đã nhận trước đây, do đó, không có sự khác biệt ở đây, ngoại trừ ký hiệu. Một ví dụ khác:
scala> modN _
res35: (Int, Int) => Boolean = <function2>
scala> modNCurried _
res36: Int => (Int => Boolean) = <function1>
này mô tả cách một phần áp dụng một "bình thường" Kết quả chức năng trong một hàm mang theo tất cả các thông số, trong khi đó áp dụng một phần chức năng với nhiều danh sách tham số tạo ra một chuỗi các chức năng, một cho mỗi danh sách tham số đó, tất cả trở lại một chức năng mới:
scala> def foo(a:Int, b:Int)(x:Int)(y:Int) = a * b + x - y
scala> foo _
res42: (Int, Int) => Int => (Int => Int) = <function2>
scala> res42(5)
<console>:10: error: not enough arguments for method apply: (v1: Int, v2: Int)Int => (Int => Int) in trait Function2.
Unspecified value parameter v2.
Như bạn có thể thấy, bởi vì danh sách tham số đầu tiên của foo
có hai thông số, chức năng đầu tiên trong chuỗi cà ri có hai tham số.
Tóm lại, các chức năng được áp dụng một phần không thực sự là các chức năng được định dạng khác nhau về chức năng.Này được dễ dàng xác minh được rằng bạn có thể chuyển đổi bất kỳ chức năng để một cà ri một:
scala> (modN _).curried
res45: Int => (Int => Boolean) = <function1
scala> modNCurried _
res46: Int => (Int => Boolean) = <function1>
bài Scriptum
Lưu ý: Lý do mà ví dụ của bạn println(filter(nums, modN(2))
công trình mà không có dấu gạch dưới sau modN(2)
dường như được rằng trình biên dịch Scala chỉ đơn giản giả định rằng gạch dưới là một tiện lợi cho lập trình viên.
Addition: Như @asflierl đã chỉ đúng ra, Scala dường như không có khả năng suy luận kiểu khi áp dụng một phần "bình thường" chức năng:
scala> modN(5, _)
<console>:9: error: missing parameter type for expanded function ((x$1) => modN(5, x$1))
Trong khi thông tin đó là có sẵn cho các hàm được viết bằng cách sử dụng nhiều ký hiệu danh sách tham số:
scala> modNCurried(5) _
res3: Int => Boolean = <function1>
This answers cho biết cách này có thể rất hữu ích.
Khi được áp dụng một phần, chi phí đại diện cho phiên bản đã được curried và không curried trong bộ nhớ * có thể khác nhau, do đó hiệu suất thời gian chạy cũng có thể bị ảnh hưởng. (Đó là, nếu trình tối ưu hóa không đủ thông minh để chọn biểu diễn tối ưu trong cả hai trường hợp.) Tôi không đủ quen thuộc với Scala để nói sự khác biệt chính xác là gì. –
Hãy xem phần này: http://stackoverflow.com/questions/8063325/usefulness-as-in-practical-applications-of-currying-vs-partial-application-i – Utaal
Tôi thấy giải thích này rất hữu ích, anh giải thích về các chức năng từng phần, chức năng được áp dụng một phần và currying, tất cả trong một bài đăng: http: //stackoverflow.com/a/8650639/1287554 –