문제

나는 아주 종종 인터넷에서 다양한 불만을 다른 사람의 예를 변환하지 않 변환,하지만 실제로 부분적인 응용 프로그램.

나는 발견되지 않았 괜찮은 무엇인지 설명 부분 응용 프로그램,또는에서 차이가 어떻게 변환.가 될 것 같다 일반적인 혼란과 함께 해당하는 예는 설명으로 변환 어떤 장소에서,그리고 부분적인 응용 프로그램에서 다른 사람입니다.

수 있는 누군가가 나에게 제공의 정의를 모두 조건의 세부사항들이 어떻게 다른가?

도움이 되었습니까?

해결책

카레는 단일 함수를 변환합니다 N 인수 N 각각 단일 인수로 기능합니다. 다음 기능이 주어지면 :

function f(x,y,z) { z(x(y));}

카레가 발생하면 :

function f(x) { lambda(y) { lambda(z) { z(x(y)); } } }

f (x, y, z)를 전체적으로 적용하려면 다음을 수행해야합니다.

f(x)(y)(z);

많은 기능적 언어를 통해 글을 쓸 수 있습니다 f x y z. 당신이 전화하는 경우 f x y 또는 f (x) (y) 그런 다음 부분적으로 적용되는 기능을 얻습니다. 반환 값은 lambda(z){z(x(y))} x와 y의 값이 전달되면 f(x,y).

부분 적용을 사용하는 한 가지 방법은 기능을 일반화 된 기능의 부분 응용 프로그램으로 정의하는 것입니다. :

function fold(combineFunction, accumulator, list) {/* ... */}
function sum     = curry(fold)(lambda(accum,e){e+accum}))(0);
function length  = curry(fold)(lambda(accum,_){1+accum})(empty-list);
function reverse = curry(fold)(lambda(accum,e){concat(e,accum)})(empty-list);

/* ... */
@list = [1, 2, 3, 4]
sum(list) //returns 10
@f = fold(lambda(accum,e){e+accum}) //f = lambda(accumulator,list) {/*...*/}
f(0,list) //returns 10
@g = f(0) //same as sum
g(list)  //returns 10

다른 팁

그들이 어떻게 다른지 보는 가장 쉬운 방법은 실제 예. 기능이 있다고 가정 해 봅시다 Add 입력으로 2 개의 숫자를 취하고 숫자를 출력으로 반환합니다. Add(7, 5) 보고 12. 이 경우 :

  • 부분 적용 함수 Add 가치와 함께 7 출력으로서 새로운 기능을 제공 할 것입니다. 해당 함수 자체는 입력으로 1 숫자를 취하고 숫자를 출력합니다. 따라서 :

    Partial(Add, 7); // returns a function f2 as output
    
                     // f2 takes 1 number as input and returns a number as output
    

    그래서 우리는 이것을 할 수 있습니다 :

    f2 = Partial(Add, 7);
    f2(5); // returns 12;
           // f2(7)(5) is just a syntactic shortcut
    
  • 카레 함수 Add 출력으로서 새로운 기능을 제공 할 것입니다. 해당 기능 자체는 입력 및 출력으로 1 숫자를 가져옵니다. 아직 또 다른 새로운 기능. 그런 다음 세 번째 함수는 입력으로 1 숫자를 취하고 출력으로 숫자를 반환합니다. 따라서 :

    Curry(Add); // returns a function f2 as output
    
                // f2 takes 1 number as input and returns a function f3 as output
                // i.e. f2(number) = f3
    
                // f3 takes 1 number as input and returns a number as output
                // i.e. f3(number) = number
    

    그래서 우리는 이것을 할 수 있습니다 :

    f2 = Curry(Add);
    f3 = f2(7);
    f3(5); // returns 12
    

다시 말해, "카레 링"과 "부분 적용"은 완전히 다른 두 가지 기능입니다. 카레는 정확히 1 입력을 사용하는 반면 부분 응용 프로그램은 2 (또는 그 이상) 입력을 취합니다.

비록 둘 다 함수를 출력으로 반환하더라도, 반환 된 함수는 위에서 설명한 바와 같이 완전히 다른 형태입니다.

참고 : 이것은 가져 왔습니다 F# 기본 .NET 개발자가 기능 프로그래밍을 시작하는 훌륭한 입문 기사.

카레는 많은 인수가있는 기능을 일련의 함수로 나누는 것을 의미하며 각각 하나의 인수를 취하고 궁극적으로 원래 함수와 동일한 결과를 생성합니다. 카레링은 아마도 기능 프로그래밍에 새로운 개발자에게 가장 어려운 주제 일 것입니다. 특히 부분 응용 프로그램과 혼동되기 때문입니다. 이 예제에서 모두 직장에서 볼 수 있습니다.

let multiply x y = x * y    
let double = multiply 2
let ten = double 5

바로, 당신은 대부분의 필수 언어와 다른 행동을 볼 수 있어야합니다. 두 번째 문장은 하나의 인수를 2 개의 함수에 전달하여 Double이라는 새로운 함수를 만듭니다. 결과는 하나의 int 인수를 받아들이고 x를 2와 동일한 x로 호출했던 것과 동일한 출력을 생산하는 함수입니다. 행동의 관점에서, 그것은이 코드와 동일합니다.

let double2 z = multiply 2 z

종종 사람들은 실수로 곱하기가 카레 (Curried)가 두 배를 형성한다고 말합니다. 그러나 이것은 다소 사실입니다. 곱셈 함수는 카레이지만 F#의 함수가 기본적으로 카레이기 때문에 정의 될 때 발생합니다. 이중 함수가 생성되면 Multiply 함수가 부분적으로 적용된다고 말하는 것이 더 정확합니다.

Multiply Function은 실제로 일련의 두 기능입니다. 첫 번째 함수는 하나의 int 인수를 취하고 다른 함수를 반환하여 x를 특정 값으로 효과적으로 바인딩합니다. 이 기능은 또한 Y에 바인딩 할 값으로 생각할 수있는 int 인수를 받아들입니다. 이 두 번째 함수를 호출 한 후 X와 Y는 둘 다 결합되므로 결과는 이중 본체에 정의 된 X와 Y의 곱입니다.

이중을 생성하기 위해, 곱하기 함수 체인의 첫 번째 함수를 평가하여 부분적으로 곱하기를 적용합니다. 결과 함수에는 이름이 두 배로 표시됩니다. Double이 평가되면 부분적으로 적용된 값과 함께 인수를 사용하여 결과를 만듭니다.

흥미로운 질문. 약간의 검색 후 "부분 함수 응용 프로그램은 카레가 아닙니다" 내가 찾은 최고의 설명을했습니다. 나는 그렇게 말할 수 없다 현실적인 차이는 특히 나에게 분명하지만, 나는 FP 전문가가 아닙니다 ...

또 다른 유용한 예술 페이지 (아직 완전히 읽지 못했다고 고백하는 것은) "Java 폐쇄로 카레 및 부분 적용".

이것은 널리 연결된 용어 인 것처럼 보입니다.

나는 이것을 다른 스레드에서 대답했다 https://stackoverflow.com/a/12846865/1685865 . 요컨대, 부분 함수 응용 프로그램은 인수가 적은 다른 기능을 생성하기 위해 주어진 다 변수 함수의 일부 인수를 고정하는 것에 관한 것이며, 카레는 n 인수의 함수를 단제 함수로 바꾸는 기능으로 바꾸는 것입니다 ... [예제. 이 게시물의 끝에 카레는 표시됩니다.

카레는 대부분 이론적 관심사입니다. 단지 기능 만 사용하여 계산을 표현할 수 있습니다 (즉 모든 기능은 단백질입니다). 실제로 및 부산물로서, 언어에 카레 기능이있는 경우, 부분적으로 기능적 응용 프로그램을 사소한 부분으로 만들 수있는 기술입니다. 다시 말하지만, 부분 응용 프로그램을 구현하는 것은 유일한 수단이 아닙니다. 따라서 부분 적용이 다른 방식으로 수행되는 시나리오를 만날 수 있지만 사람들은 카레를 화려하게하고 있습니다.

(카레의 예)

실제로는 글을 쓰지 않을 것입니다

lambda x: lambda y: lambda z: x + y + z

또는 동등한 JavaScript

function (x) { return function (y){ return function (z){ return x + y + z }}}

대신에

lambda x, y, z: x + y + z

카레를 위해.

카레는 기능입니다 하나 기능을 취하는 인수 f 새로운 기능을 반환합니다 h. 주목하십시오 h 논쟁을 취합니다 X 그리고 반환 a 기능 그지도 Y 에게 Z:

curry(f) = h 
f: (X x Y) -> Z 
h: X -> (Y -> Z)

부분 응용 프로그램은의 함수입니다 두 개 (또는 그 이상) 기능을 취하는 인수 f 그리고 하나 이상의 추가 논쟁 f 새로운 기능을 반환합니다 g:

part(f, 2) = g
f: (X x Y) -> Z 
g: Y -> Z

혼란은 두 가지 관점 기능으로 다음 평등이 유지되기 때문에 발생합니다.

partial(f, a) = curry(f)(a)

양쪽은 동일한 1-론 기능을 생성합니다.

이 경우 카레는 한 번의 연계 기능을 반환하는 반면, 부분 적용은 다중 연계 기능을 반환하기 때문에 평등은 아티리티 기능에 대해서는 사실이 아닙니다.

차이는 행동에도 있지만, 카레는 전체 원래 함수를 재귀 적으로 변형시키는 반면 (각 인수에 대해 한 번) 부분 적용은 단 한 단계 교체품입니다.

원천: Wikipedia 카레.

카레와 부분 적용의 차이점은 다음 JavaScript 예를 통해 가장 잘 설명 할 수 있습니다.

function f(x, y, z) {
    return x + y + z;
}

var partial = f.bind(null, 1);

6 === partial(2, 3);

부분 적용은 작은 아티브의 기능을 초래합니다. 위의 예에서 f 3의 아티브가 있습니다 partial 더 중요한 것은 부분적으로 적용되는 기능은 2입니다. 호출되면 결과를 즉시 반환하십시오, 카레이 체인 아래에 다른 기능이 아닙니다. 그래서 당신이 같은 것을보고 있다면 partial(2)(3), 실제로는 부분적으로 적용되지 않습니다.

추가 읽기 :

나에게 부분 응용 프로그램은 사용 된 인수가 결과 함수에 완전히 통합되는 새 기능을 만들어야합니다.

대부분의 기능 언어는 폐쇄를 반환하여 카레를 구현합니다. 부분적으로 적용될 때 Lambda에서 평가하지 마십시오. 따라서 부분 적용이 흥미로워 지려면 카레와 부분 적용을 차이를 만들고 Lambda의 카레 링 플러스 평가로 부분 적용을 고려해야합니다.

이론적 수학이나 기능적 프로그래밍에 대한 강력한 배경이 없기 때문에 여기서는 매우 잘못 될 수 있지만, 간단한 FP로의 발표에서 카레는 N 인수의 함수를 하나의 인수의 N 기능으로 바꾸는 경향이있는 것 같습니다. 반면 부분적으로 [실제로]는 불확실한 수의 인수를 가진 변수 함수로 더 잘 작동합니다. 이전 답변의 몇 가지 예가이 설명을 무시하지만 개념을 분리하는 데 가장 큰 도움이되었습니다. 이 예를 고려하십시오 (간결하게 CoffeeScript로 작성, 더 혼란스러워지면 사과하지만 필요한 경우 설명을 요청하십시오).

# partial application
partial_apply = (func) ->
  args = [].slice.call arguments, 1
  -> func.apply null, args.concat [].slice.call arguments

sum_variadic = -> [].reduce.call arguments, (acc, num) -> acc + num

add_to_7_and_5 = partial_apply sum_variadic, 7, 5

add_to_7_and_5 10 # returns 22
add_to_7_and_5 10, 11, 12 # returns 45

# currying
curry = (func) ->
  num_args = func.length
  helper = (prev) ->
    ->
      args = prev.concat [].slice.call arguments
      return if args.length < num_args then helper args else func.apply null, args
  helper []

sum_of_three = (x, y, z) -> x + y + z
curried_sum_of_three = curry sum_of_three
curried_sum_of_three 4 # returns a function expecting more arguments
curried_sum_of_three(4)(5) # still returns a function expecting more arguments
curried_sum_of_three(4)(5)(6) # returns 15
curried_sum_of_three 4, 5, 6 # returns 15

이것은 분명히 고안된 예이지만, 여러 인수를 받아들이는 함수를 부분적으로 적용하면 기능을 실행할 수 있지만 일부 예비 데이터를 사용합니다. 함수 카레는 비슷하지만 N-Parameter 함수를 한 조각으로 실행할 수는 있지만 모든 n 매개 변수가 설명 될 때까지만.

다시 말하지만, 이것은 내가 읽은 것들에서 가져온 것입니다. 누군가 동의하지 않는다면, 즉각적인 다운 보트가 아닌 이유에 대한 의견에 감사드립니다. 또한 Coffeescript를 읽기 어려운 경우 Coffeescript.org를 방문하여 "Coffeescript를 시도해보십시오"를 클릭하고 내 코드에 붙여 넣어 컴파일 된 버전을 확인하십시오. 감사!

나는 배우 면서이 질문을 많이했으며 그 이후로 여러 번 질문을 받았습니다. 차이를 설명 할 수있는 가장 간단한 방법은 둘 다 동일하다는 것입니다. :) 설명하겠습니다 ... 분명히 차이가 있습니다.

부분 적용과 카레 링은 기능에 인수를 제공하는 것이 포함되며, 아마도 한 번에 전부는 아닙니다. 상당히 정식적인 예는 두 숫자를 추가하는 것입니다. 의사 코드 (실제로 키워드가없는 JS)에서 기본 함수는 다음과 같습니다.

add = (x, y) => x + y

"addone"기능을 원한다면 부분적으로 적용하거나 카레를 사용할 수 있습니다.

addOneC = curry(add, 1)
addOneP = partial(add, 1)

이제 그것들을 사용하는 것이 분명합니다.

addOneC(2) #=> 3
addOneP(2) #=> 3

그래서 차이점은 무엇입니까? 글쎄, 그것은 미묘하지만, 부분 적용은 일부 인수를 제공하는 것이 포함되며 반환 된 기능은 그러면 반환 된 기능이 있습니다. 다음 호출시 기본 기능을 실행하십시오 반면 카레는 필요한 모든 주장이있을 때까지 계속 기다릴 것입니다.

curriedAdd = curry(add) # notice, no args are provided
addOne = curriedAdd(1) # returns a function that can be used to provide the last argument
addOne(2) #=> returns 3, as we want

partialAdd = partial(add) # no args provided, but this still returns a function
addOne = partialAdd(1) # oops! can only use a partially applied function once, so now we're trying to add one to an undefined value (no second argument), and we get an error

요컨대, 부분적 응용 프로그램을 사용하여 일부 값을 시사하여 다음에 메소드를 호출 할 때 실행되며 정의되지 않은 모든 인수를 남겨 두는 것이 실행된다는 것을 알게됩니다. 기능 서명을 수행하기 위해 필요한만큼 부분적으로 적용되는 기능을 지속적으로 반환하려는 경우 카레 사용을 사용하십시오. 마지막으로 고안된 한 가지 예 :

curriedAdd = curry(add)
curriedAdd()()()()()(1)(2) # ugly and dumb, but it works

partialAdd = partial(add)
partialAdd()()()()()(1)(2) # second invocation of those 7 calls fires it off with undefined parameters

도움이 되었기를 바랍니다!

업데이트 : 일부 언어 또는 LIB 구현으로 인해 두 가지 설명을 혼란스러운 혼란으로 혼란시킬 수있는 부분 응용 프로그램 구현에 아티브 (최종 평가의 총 주장 수)를 전달할 수 있습니다. 그러나 그 시점에서 두 기술은 두 가지 기술입니다. 크게 상호 교환 가능합니다.

간단한 답변

카레: 함수를 호출하여 여러 통화로 분할하여 하나의 인수 당 하나의 인수를 제공 할 수 있습니다.

부분 : 함수를 호출하여 여러 통화로 분할하여 여러 인수 당사자 당사자를 제공 할 수 있습니다.


간단한 힌트

둘 다 덜 인수를 제공하는 함수를 호출 할 수 있습니다 (또는 더 나은, 누적으로 제공). 실제로 둘 다 함수의 특정 인수에 대한 특정 값을 (각 호출에서) 바인딩합니다.

함수에 2 개 이상의 인수가있을 때 실제 차이점을 볼 수 있습니다.


간단한 E (C) (샘플)

(JavaScript에서)

function process(context, success_callback, error_callback, subject) {...}

항상 컨텍스트 나 콜백과 같은 인수가 항상 동일하다면 왜 항상 인수를 전달합니까? 함수에 대한 값을 바인딩하십시오

processSubject = _.partial(process, my_context, my_success, my_error)

그리고 그것을 불러주세요 주제 1 그리고 foobar ~와 함께

processSubject('subject1');
processSubject('foobar');

편안하지 않습니까? 😉

와 함께 카레 시간당 하나의 인수를 통과해야합니다

curriedProcess = _.curry(process);
processWithBoundedContext = curriedProcess(my_context);
processWithCallbacks = processWithBoundedContext(my_success)(my_error); // note: these are two sequential calls

result1 = processWithCallbacks('subject1');
// same as: process(my_context, my_success, my_error, 'subject1');
result2 = processWithCallbacks('foobar'); 
// same as: process(my_context, my_success, my_error, 'foobar');

부인 성명

나는 모든 학업/수학적 설명을 건너 뛰었습니다. 나는 그것을 모르기 때문에. 어쩌면 그것은 도움이되었을 것입니다

다른 훌륭한 답변을 여기에서 그러나 나는 이것을 믿는 예(당으로 나의 이해)자바에서 도움이 될 수있는 일부 사람들:

public static <A,B,X> Function< B, X > partiallyApply( BiFunction< A, B, X > aBiFunction, A aValue ){
    return b -> aBiFunction.apply( aValue, b );
}

public static <A,X> Supplier< X > partiallyApply( Function< A, X > aFunction, A aValue ){
    return () -> aFunction.apply( aValue );
}

public static <A,B,X> Function<  A, Function< B, X >  > curry( BiFunction< A, B, X > bif ){
    return a -> partiallyApply( bif, a );
}

그래서 변환을 제공 합 one-인수 기능 함수를 만들 곳,부분-응용 프로그램을 만듭니다 래퍼 함수는 코드는 하나 이상의 인수입니다.

하려면 복사&붙여넣기,다음은 잡음이지만 친근과 작업하기 때문 형식은 더 많은 관대:

public static <A,B,X> Function< ? super B, ? extends X > partiallyApply( final BiFunction< ? super A, ? super B, X > aBiFunction, final A aValue ){
    return b -> aBiFunction.apply( aValue, b );
}

public static <A,X> Supplier< ? extends X > partiallyApply( final Function< ? super A, X > aFunction, final A aValue ){
    return () -> aFunction.apply( aValue );
}

public static <A,B,X> Function<  ? super A,  Function< ? super B, ? extends X >  > curry( final BiFunction< ? super A, ? super B, ? extends X > bif ){
    return a -> partiallyApply( bif, a );
}

이것을 쓰면서, 나는 카레와 urrying을 혼란스럽게했다. 그들은 함수에 대한 역 변환입니다. 당신이 무엇을 부르는지는 당신이 무엇을 부르는지는 중요하지 않습니다.

urrying은 매우 명확하게 정의되지 않았습니다 (또는 오히려 아이디어의 정신을 포착하는 "충돌하는"정의가 있습니다). 기본적으로 여러 인수를 하나의 인수를 취하는 함수로 전환하는 함수를 의미합니다. 예를 들어,

(+) :: Int -> Int -> Int

이제 이것을 하나의 인수를 취하는 함수로 어떻게 바꾸나요? 물론 당신은 속임수입니다!

plus :: (Int, Int) -> Int

플러스는 이제 하나의 논쟁을 취합니다 (이것은 두 가지로 구성됨). 감독자!

이것의 요점은 무엇입니까? 글쎄, 두 가지 인수를 취하는 기능이 있고 한 쌍의 인수가 있다면 기능을 인수에 적용하고 여전히 기대하는 것을 얻을 수 있다는 것을 아는 것이 좋습니다. 그리고 실제로, 배관을하기위한 배관은 이미 존재하므로 명시 적 패턴 일치와 같은 일을 할 필요가 없습니다. 당신이해야 할 일은 다음과 같습니다.

(uncurry (+)) (1,2)

그렇다면 부분 기능 응용 프로그램이란 무엇입니까? 두 인수의 함수를 하나의 인수가있는 함수로 바꾸는 다른 방법입니다. 그래도 다르게 작동합니다. 다시 한 번 (+)를 예로 들어 봅시다. 하나의 int를 인수로 취하는 함수로 어떻게 전환 할 수 있습니까? 우리는 속임수!

((+) 0) :: Int -> Int

그것이 모든 int에 0을 더하는 함수입니다.

((+) 1) :: Int -> Int

모든 int에 1을 추가합니다. 각각의 경우 (+)가 "부분적으로 적용"됩니다.

나는이 질문을하는 대부분의 사람들이 이미 기본 개념에 익숙하다고 가정하므로 그것에 대해 이야기 할 필요가 없습니다. 혼란스러운 부분 인 겹침입니다.

개념을 완전히 사용할 수는 있지만이 의사 원자 무정형 개념적 흐림으로 함께 이해합니다. 누락 된 것은 그들 사이의 경계가 어디에 있는지 아는 것입니다.

각각이 무엇인지 정의하는 대신, 차이점, 즉 경계를 강조하는 것이 더 쉽습니다.

카레 당신이있을 때입니다 정의하다 함수.

부분 적용 당신이있을 때입니다 전화 함수.

신청 함수를 호출하기위한 수학 말입니다.

부분적 응용 프로그램은 카레 기능을 호출하고 반환 유형으로 함수를 가져와야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top