Groovy thực hiện curry
khô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
, rcurry
và ncurry
phươ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 invokeMethod
phươ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 curry
phươ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 partial
hà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 curry
là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 curry
là 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ì addCurried
nê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.