문제

여러 기사와 블로그에서 카레 함수에 대한 참조를 보았지만 좋은 설명(또는 적어도 이해가 되는 설명)을 찾을 수 없습니다.

도움이 되었습니까?

해결책

커링은 여러 인수를 취하는 함수를 인수의 일부를 취하는 일련의 함수로 분해하는 것입니다.다음은 JavaScript의 예입니다.

function add (a, b) {
  return a + b;
}

add(3, 4); // returns 7

이것은 두 개의 인수 a와 b를 취하고 그 합을 반환하는 함수입니다.이제 이 함수를 카레할 것입니다:

function add (a) {
  return function (b) {
    return a + b;
  }
}

이는 하나의 인수 a를 사용하고 다른 인수 b를 사용하는 함수를 반환하는 함수이며 해당 함수는 해당 합계를 반환합니다.

add(3)(4);

var add3 = add(3);

add3(4);

첫 번째 문은 add(3, 4) 문과 마찬가지로 7을 반환합니다.두 번째 명령문은 인수에 3을 더하는 add3이라는 새 함수를 정의합니다.이것을 어떤 사람들은 폐쇄라고 부를 수도 있습니다.세 번째 문은 add3 작업을 사용하여 3을 4에 더하고 결과적으로 다시 7을 생성합니다.

다른 팁

함수의 대수학에서 여러 인수(또는 N-튜플에 해당하는 하나의 인수)를 취하는 함수를 다루는 것은 다소 우아하지 않습니다. 하지만 Moses Schönfinkel(및 독립적으로 Haskell Curry)이 증명했듯이 필요하지 않습니다.필요한 것은 하나의 인수를 취하는 함수뿐입니다.

그렇다면 자연스럽게 표현하는 것을 어떻게 처리합니까? f(x,y)?글쎄, 당신은 그것을 동등하다고 생각합니다 f(x)(y) -- f(x), 불러라 g, 는 함수이며 해당 함수를 다음에 적용합니다. y.즉, 하나의 인수를 취하는 함수만 있지만 이러한 함수 중 일부는 다른 함수를 반환합니다(또한 하나의 인수를 취함).

평소처럼, 위키피디아 여기에는 많은 유용한 포인터(아마도 좋아하는 언어에 관한 포인터 포함)와 약간 더 엄격한 수학적 처리가 포함된 멋진 요약 항목이 있습니다.

구체적인 예는 다음과 같습니다.

물체에 작용하는 중력을 계산하는 함수가 있다고 가정해 보겠습니다.공식을 모르신다면 찾아보세요 여기.이 함수는 세 가지 필수 매개변수를 인수로 사용합니다.

이제 지구에 있으면서 이 행성에 있는 물체에 대한 힘만 계산하려고 합니다.함수형 언어에서는 지구의 질량을 함수에 전달한 다음 부분적으로 평가할 수 있습니다.당신이 돌려받을 것은 두 개의 인수만 취하고 지구상 물체의 중력을 계산하는 또 다른 함수입니다.이것을 커링이라고 합니다.

커링(Currying)은 함수에 적용하여 이전보다 인수를 하나 적게 취할 수 있도록 하는 변환입니다.

예를 들어 F#에서는 다음과 같이 함수를 정의할 수 있습니다.

let f x y z = x + y + z

여기서 함수 f는 매개변수 x, y 및 z를 취해 이를 합산합니다.

f 1 2 3

6을 반환합니다.

따라서 우리의 정의로부터 f:-에 대한 카레 함수를 정의할 수 있습니다.

let curry f = fun x -> f x

여기서 'fun x -> f x'는 C#의 x => f(x)에 해당하는 람다 함수입니다.이 함수는 커리하려는 함수를 입력하고 해당 함수를 반환합니다. 단일 인수를 사용합니다. 그리고 첫 번째 인수가 입력 인수로 설정된 지정된 함수를 반환합니다.

이전 예제를 사용하여 f의 카레를 얻을 수 있습니다.

let curryf = curry f

그런 다음 다음을 수행할 수 있습니다.

let f1 = curryf 1

이는 f1 y z = 1 + y + z와 동등한 함수 f1을 제공합니다.이는 다음을 수행할 수 있음을 의미합니다.

f1 2 3

6을 반환합니다.

이 프로세스는 다음과 같이 정의할 수 있는 '부분 함수 적용'과 종종 혼동됩니다.

let papply f x = f x

하지만 이를 하나 이상의 매개변수로 확장할 수 있습니다. 즉:-

let papply2 f x y = f x y
let papply3 f x y z = f x y z
etc.

부분 애플리케이션은 함수와 매개 변수를 가져와 하나 이상의 매개 변수가 필요한 함수를 반환합니다. 이전 두 예제에서 볼 수 있듯이 표준 F# 함수 정의에서 직접 구현되므로 이전 결과를 얻을 수 있습니다.

let f1 = f 1
f1 2 3

결과는 6이 반환됩니다.

결론적으로:-

카레링과 부분 기능 적용의 차이점은 다음과 같습니다.

커링은 함수를 취하고 단일 인수를 받아들이고 첫 번째 인수가 해당 인수로 설정된 지정된 함수를 반환하는 새 함수를 제공합니다. 이를 통해 여러 매개변수가 있는 함수를 일련의 단일 인수 함수로 표현할 수 있습니다..예:-

let f x y z = x + y + z
let curryf = curry f
let f1 = curryf 1
let f2 = curryf 2
f1 2 3
6
f2 1 3
6

부분 함수 적용은 더 직접적입니다. 함수와 하나 이상의 인수를 사용하고 지정된 n 인수로 설정된 처음 n 인수가 있는 함수를 반환합니다.예:-

let f x y z = x + y + z
let f1 = f 1
let f2 = f 2
f1 2 3
6
f2 1 3
6

함수를 사용하여 다른 함수를 만드는 방법이 될 수 있습니다.

자바스크립트에서:

let add = function(x){
  return function(y){ 
   return x + y
  };
};

다음과 같이 호출할 수 있습니다.

let addTen = add(10);

이것이 실행될 때 10 다음과 같이 전달됩니다. x;

let add = function(10){
  return function(y){
    return 10 + y 
  };
};

이는 다음 함수가 반환된다는 의미입니다.

function(y) { return 10 + y };

그래서 전화할 때

 addTen();

당신은 정말로 전화하고 있습니다 :

 function(y) { return 10 + y };

따라서 이렇게 하면:

 addTen(4)

그것은 다음과 같습니다:

function(4) { return 10 + 4} // 14

그래서 우리의 addTen() 우리가 전달하는 모든 것에 항상 10을 더합니다.같은 방식으로 비슷한 기능을 만들 수 있습니다.

let addTwo = add(2)       // addTwo(); will add two to whatever you pass in
let addSeventy = add(70)  // ... and so on...

카레 함수는 첫 번째 인수를 받아들이고 두 번째 인수를 받아들이는 함수를 반환하도록 다시 작성된 여러 인수의 함수입니다.이를 통해 여러 인수의 함수에 초기 인수 중 일부를 부분적으로 적용할 수 있습니다.

다음은 Python의 장난감 예제입니다.

>>> from functools import partial as curry

>>> # Original function taking three parameters:
>>> def display_quote(who, subject, quote):
        print who, 'said regarding', subject + ':'
        print '"' + quote + '"'


>>> display_quote("hoohoo", "functional languages",
           "I like Erlang, not sure yet about Haskell.")
hoohoo said regarding functional languages:
"I like Erlang, not sure yet about Haskell."

>>> # Let's curry the function to get another that always quotes Alex...
>>> am_quote = curry(display_quote, "Alex Martelli")

>>> am_quote("currying", "As usual, wikipedia has a nice summary...")
Alex Martelli said regarding currying:
"As usual, wikipedia has a nice summary..."

(Python 프로그래머가 아닌 사람들의 주의가 산만해지지 않도록 +를 통해 연결을 사용하면 됩니다.)

추가 편집:

보다 http://docs.python.org/library/functools.html?highlight=partial#functools.partial, 또한 부분 객체 대를 보여줍니다.Python이 이를 구현하는 방식으로 함수를 구별합니다.

이해한다면 partial 절반쯤 왔습니다.아이디어 partial 함수에 인수를 미리 적용하고 나머지 인수만 원하는 새 함수를 반환하는 것입니다.이 새 함수가 호출되면 여기에 제공된 인수와 함께 미리 로드된 인수가 포함됩니다.

클로저에서 + 함수이지만 상황을 완전히 명확하게 하기 위해 다음과 같이 합니다.

(defn add [a b] (+ a b))

당신은 inc 함수는 단순히 전달된 숫자에 1을 더합니다.

(inc 7) # => 8

다음을 사용하여 직접 만들어 보겠습니다. partial:

(def inc (partial add 1))

여기서는 첫 번째 인수에 1이 로드된 또 다른 함수를 반환합니다. add.처럼 add 새로운 인수 두 개를 취합니다. inc 함수는 오직 b 인수 - 1개의 인수가 이미 있으므로 이전처럼 2개의 인수가 아닙니다. 부분적으로 적용된.따라서 partial 미리 제공된 기본값을 사용하여 새 기능을 생성하는 도구입니다.이것이 바로 함수형 언어에서 함수가 인수의 순서를 일반적인 것에서 구체적인 것으로 정렬하는 이유입니다.이렇게 하면 다른 기능을 구성하는 데 사용할 수 있는 기능을 더 쉽게 재사용할 수 있습니다.

이제 언어가 다음을 내성적으로 이해할 만큼 똑똑하다고 상상해 보세요. add 두 가지 주장을 원했습니다.우리가 당황하지 않고 하나의 인수를 전달할 때 함수가 나중에 다른 인수를 제공할 의도가 있다는 것을 이해하여 우리를 대신하여 인수를 부분적으로 적용했다면 어떻게 될까요?그러면 우리는 다음을 정의할 수 있습니다. inc 명시적으로 사용하지 않고 partial.

(def inc (add 1)) #partial is implied

이것이 일부 언어가 작동하는 방식입니다.함수를 더 큰 변환으로 구성하려는 경우 매우 유용합니다.이것은 변환기로 이어질 것입니다.

커링을 더 잘 이해하는 데 이 기사와 이 기사에서 참조하는 기사가 유용하다는 것을 알았습니다.http://blogs.msdn.com/wesdyer/archive/2007/01/29/currying-and-partial-function-application.aspx

다른 사람들이 언급했듯이 이는 하나의 매개변수 기능을 갖는 방법일 뿐입니다.

이는 얼마나 많은 매개변수가 전달될지 가정할 필요가 없으므로 2개 매개변수, 3개 매개변수 및 4개 매개변수 함수가 필요하지 않다는 점에서 유용합니다.

Curry는 코드를 단순화할 수 있습니다.이것이 이것을 사용하는 주요 이유 중 하나입니다.커링은 n개의 인수를 받는 함수를 하나의 인수만 받는 n개의 함수로 변환하는 과정입니다.

전달된 함수의 인수를 클로저(클로저) 속성을 사용하여 전달하여 다른 함수에 저장하고 반환 값으로 처리하며 이러한 함수가 체인을 형성하고 최종 인수가 전달되어 완료되는 것이 원칙입니다. 작업.

이것의 장점은 한 번에 하나의 매개변수를 처리하여 매개변수 처리를 단순화할 수 있고 프로그램의 유연성과 가독성도 향상시킬 수 있다는 것입니다.이는 또한 프로그램을 보다 관리하기 쉽게 만듭니다.또한 코드를 더 작은 조각으로 나누면 재사용하기 쉬워집니다.

예를 들어:

function curryMinus(x) 
{
  return function(y) 
  {
    return x - y;
  }
}

var minus5 = curryMinus(1);
minus5(3);
minus5(5);

나도 할 수 있어...

var minus7 = curryMinus(7);
minus7(3);
minus7(5);

이는 복잡한 코드를 깔끔하게 만들고 비동기화된 메서드 등을 처리하는 데 매우 유용합니다.

커링은 호출 가능한 함수를 다음과 같이 변환합니다. f(a, b, c) 호출 가능으로 f(a)(b)(c).

그렇지 않으면 커링은 여러 인수를 취하는 함수를 인수의 일부를 취하는 일련의 함수로 분해하는 것입니다.

말 그대로 커링은 함수를 변형한 것입니다.한 가지 방법으로 다른 방법을 호출합니다.JavaScript에서는 일반적으로 원래 기능을 유지하기 위해 래퍼를 만듭니다.

커링은 함수를 호출하지 않습니다.단지 그것을 변화시킬 뿐입니다.

두 개의 인수 함수에 대해 커링을 수행하는 커리 함수를 만들어 보겠습니다.다시 말해서, curry(f) 두 인수의 경우 f(a, b) 그것을 다음과 같이 번역한다 f(a)(b)

function curry(f) { // curry(f) does the currying transform
  return function(a) {
    return function(b) {
      return f(a, b);
    };
  };
}

// usage
function sum(a, b) {
  return a + b;
}

let carriedSum = curry(sum);

alert( carriedSum(1)(2) ); // 3

보시다시피 구현은 일련의 래퍼입니다.

  • 결과 curry(func) 포장지입니다 function(a).
  • 다음과 같이 호출될 때 sum(1), 인수는 어휘 환경에 저장되고 새 래퍼가 반환됩니다. function(b).
  • 그 다음에 sum(1)(2) 마침내 전화 function(b) 2를 제공하면 호출을 원래 다중 인수 합계로 전달합니다.

카레 기능은 단지 하나가 아닌 여러 인수 목록에 적용됩니다.

다음은 정기적 인 비 큐리스 함수이며, 두 개의 int 매개 변수 x와 y를 추가합니다.

scala> def plainOldSum(x: Int, y: Int) = x + y
plainOldSum: (x: Int,y: Int)Int
scala> plainOldSum(1, 2)
res4: Int = 3

여기에 카레와 비슷한 기능이 있습니다.두 개의 int 매개 변수 목록 대신이 기능을 각각 하나의 int 매개 변수 목록에 적용합니다.

scala> def curriedSum(x: Int)(y: Int) = x + y
curriedSum: (x: Int)(y: Int)Intscala> second(2)
res6: Int = 3
scala> curriedSum(1)(2)
res5: Int = 3

여기서 일어나는 일은 curriedSum, 실제로 두 개의 전통적인 함수 호출이 연속적으로 발생합니다.첫 번째 함수 호출은 이름이 지정된 단일 INT 매개 변수를 취합니다. x 두 번째 함수의 함수 값을 반환합니다.이 두 번째 함수는 Int 매개변수를 사용합니다.y.

여기에 이름이 붙은 함수가 있습니다. first 그것은 최초의 전통적인 기능 호출이 curriedSum 할것이다:

scala> def first(x: Int) = (y: Int) => x + y
first: (x: Int)(Int) => Int

첫 번째 함수, 즉 첫 번째 함수에 1을 적용하고 첫 번째 함수를 호출하고 1을 전달합니다 - 두 번째 함수는 다음과 같습니다.

scala> val second = first(1)
second: (Int) => Int = <function1>

두 번째 함수에 2를 적용하면 다음과 같은 결과가 나옵니다.

scala> second(2)
res6: Int = 3

커링의 예는 현재 매개변수 중 하나만 알고 있는 함수가 있는 경우입니다.

예를 들어:

func aFunction(str: String) {
    let callback = callback(str) // signature now is `NSData -> ()`
    performAsyncRequest(callback)
}

func callback(str: String, data: NSData) {
    // Callback code
}

func performAsyncRequest(callback: NSData -> ()) {
    // Async code that will call callback with NSData as parameter
}

여기서는 콜백을 보낼 때 콜백의 두 번째 매개변수를 모르기 때문에 performAsyncRequest(_:) 이를 함수에 보내려면 또 다른 람다/클로저를 만들어야 합니다.

다른 모든 답변과 마찬가지로 카레는 부분적으로 적용되는 기능을 만드는 데 도움이 됩니다.Javascript는 자동 커링에 대한 기본 지원을 제공하지 않습니다.따라서 위에 제공된 예제는 실제 코딩에 도움이 되지 않을 수 있습니다.라이브 스크립트에는 몇 가지 훌륭한 예가 있습니다(기본적으로 js로 컴파일됨).http://livescript.net/

times = (x, y) --> x * y
times 2, 3       #=> 6 (normal use works as expected)
double = times 2
double 5         #=> 10

위의 예에서 인수를 적게 지정하면 livescript가 새로운 카레 함수를 생성합니다(이중).

여기에서 C#의 카레 구현에 대한 간단한 설명을 찾을 수 있습니다.댓글에서 나는 커링이 어떻게 유용할 수 있는지 보여주려고 노력했습니다.

public static class FuncExtensions {
    public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> func)
    {
        return x1 => x2 => func(x1, x2);
    }
}

//Usage
var add = new Func<int, int, int>((x, y) => x + y).Curry();
var func = add(1);

//Obtaining the next parameter here, calling later the func with next parameter.
//Or you can prepare some base calculations at the previous step and then
//use the result of those calculations when calling the func multiple times 
//with different input parameters.

int result = func(1);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top