Groovy thực hiện currykhông thực sự cà ri tại bất kỳ điểm nào, ngay cả đằng sau hậu trường. Nó về cơ bản là giống hệt với ứng dụng một phần.
Các curry, rcurryvà ncurryphương pháp trả về một CurriedClosuređối tượng chứa các đối số ràng buộc. Nó cũng có một phương thức getUncurriedArguments(được đặt tên sai là các hàm cà ri của bạn chứ không phải các đối số) trả về thành phần của các đối số được truyền cho nó với các đối số bị ràng buộc.
Khi đóng cửa được gọi, nó cuối cùng gọi các invokeMethodphương phápMetaClassImpl , mà rõ ràng kiểm tra xem nếu đối tượng gọi là một thể hiện của CurriedClosure. Nếu vậy, nó sử dụng đã nói ở trên getUncurriedArgumentsđể soạn toàn bộ các đối số để áp dụng:
if (objectClass == CurriedClosure.class) {
// ...
final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
// [Ed: Yes, you read that right, curried = uncurried. :) ]
// ...
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
Dựa trên danh pháp khó hiểu và có phần không nhất quán ở trên, tôi nghi ngờ rằng bất cứ ai viết bài này đều có một sự hiểu biết khái niệm tốt, nhưng có lẽ hơi vội vàng và giống như nhiều người thông minh, đã kết hợp cà ri với ứng dụng một phần. Điều này có thể hiểu được (xem câu trả lời của Paul King), nếu không may; sẽ rất khó để sửa lỗi này mà không phá vỡ tính tương thích ngược.
Một giải pháp mà tôi đã đề xuất là quá tải curryphương thức sao cho khi không có đối số nào được thông qua, nó sẽ thực hiện quá trình curry thực sự và không dùng phương thức đó với các đối số có lợi cho partialhàm mới . Điều này có vẻ hơi lạ , nhưng nó sẽ tối đa hóa khả năng tương thích ngược vì vì không có lý do gì để sử dụng ứng dụng một phần với các đối số bằng 0 trong khi tránh tình huống xấu hơn (IMHO) khi có một chức năng mới, được đặt tên khác để thực hiện chức năng cà ri trong khi thực sự chức năng được đặt tên currylàm một cái gì đó khác nhau và tương tự khó hiểu.
Không cần phải nói rằng kết quả của cuộc gọi currylà hoàn toàn khác với cà ri thực tế. Nếu nó thực sự làm hỏng chức năng, bạn sẽ có thể viết:
def add = { x, y -> x + y }
def addCurried = add.curry() // should work like { x -> { y -> x + y } }
def add1 = addCurried(1) // should work like { y -> 1 + y }
assert add1(1) == 2
Càng và nó sẽ hoạt động, vì addCurriednên làm việc như thế nào { x -> { y -> x + y } }. Thay vào đó, nó ném một ngoại lệ thời gian chạy và bạn chết một chút bên trong.