Groovy의 구현은 curry
장면 뒤에서조차 실제로 어떤 시점에서도 카레하지 않습니다. 본질적으로 부분 적용과 동일합니다.
curry
, rcurry
및 ncurry
방법은 반환 CurriedClosure
객체 바인딩 인수를 보유하고 있습니다. 또한 getUncurriedArguments
바인딩 된 인수와 함께 전달 된 인수의 구성을 반환 하는 메서드 (인수가 아닌 함수를 카레 함)가 있습니다.
클로저가 호출되면 궁극적으로 의 invokeMethod
메소드를MetaClassImpl
호출하여 호출 객체가의 인스턴스인지 여부를 명시 적으로 확인합니다 CurriedClosure
. 그렇다면 위에서 언급 한 내용 getUncurriedArguments
을 사용 하여 전체 인수 배열을 작성하여 적용하십시오.
if (objectClass == CurriedClosure.class) {
// ...
final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
// [Ed: Yes, you read that right, curried = uncurried. :) ]
// ...
return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
}
위의 혼란스럽고 다소 일관성이없는 명명법을 바탕으로,이 글을 쓴 사람은 개념에 대한 이해가 좋았지 만, 많은 똑똑한 사람들처럼 약간의 서두르고 부분적인 적용으로 카레가 부풀려 졌을 것입니다. 불행히도 이것은 이해할 만합니다 (폴 킹의 답변 참조). 이전 버전과의 호환성을 유지하지 않으면이 문제를 해결하기가 어렵습니다.
내가 제안한 한 가지 해결책 은 curry
인수가 전달되지 않을 때 실제로 카레를 수행하고 새로운 partial
함수 를 선호하는 인수로 메소드 호출을 더 이상 사용 하지 않도록 메소드 를 오버로드하는 것입니다. 이것은 조금 이상하게 보일지 모르지만, 인수가 0 인 부분 응용 프로그램을 사용할 이유가 없기 때문에 이전 버전과의 호환성을 최대화 할 것입니다. 함수가 실제로있는 동안 올바른 카레를 위해 다른 이름이 지정된 새로운 기능을 갖는 (IMHO) 더 추악한 상황을 피하십시오. named curry
는 다르고 혼란스럽게 비슷한 것을합니다.
전화 결과는 curry
실제 카레와 완전히 다릅니다. 실제로 함수를 커리면 다음과 같이 쓸 수 있습니다.
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
… 그리고 작동 addCurried
해야 하기 때문에 작동 { x -> { y -> x + y } }
합니다. 대신 런타임 예외가 발생하고 내부에서 약간 죽습니다.