문제

나는 개념을 파악하기 위해 여러 번 시도했습니다 연속 그리고 전화/cc. 모든 시도는 실패였습니다. Wikipedia 또는 다른 SO 게시물에서보다 더 현실적인 예제가 이상적 으로이 개념을 설명해 주시겠습니까?

웹 프로그래밍 및 OOP에 대한 배경 지식이 있습니다. 나는 또한 6502 어셈블리를 이해하고 Erlang과 작은 Randez-Vous를 가지고있었습니다. 그러나 여전히 Call/CC 주위에 머리를 감을 수 없습니다.

도움이 되었습니까?

해결책

봐, 나는 이것을 찾았다 계속 통과 스타일 이 주제에 대한 최고의 설명.

다음은 해당 기사의 세부 사항 사본을 제거했습니다.

저자 : Marijn Haverbeke 날짜 : 2007 년 7 월 24 일

Scheme의 통화-전류 연락 함수를 사용하면 계산, 통화 스택 상태가있는 상태를 캡처하고 나중에 동일한 상태를 재개 할 수 있습니다. 이러한 원시적, 다양한 형태의 예외 처리 및 C와 유사한 LongJMP 트릭을 구현할 수 있습니다.

function traverseDocument(node, func) {
  func(node);
  var children = node.childNodes;
  for (var i = 0; i < children.length; i++)
    traverseDocument(children[i], func);
}   

function capitaliseText(node) {
  if (node.nodeType == 3) // A text node
    node.nodeValue = node.nodeValue.toUpperCase();
}

traverseDocument(document.body, capitaliseText);

이것은 다음과 같이 변형 될 수 있습니다. 우리는 모든 함수에 추가 인수를 추가하여 함수의 연속을 통과하는 데 사용됩니다. 이 연속은 함수 'returns'후에 발생 해야하는 동작을 나타내는 기능 값입니다. (Call) 스택은 연속 통과 스타일에서 쓸모 없게됩니다. 함수가 다른 함수를 호출 할 때 마지막 일입니다. 호출 된 함수가 돌아 오기를 기다리는 대신, 나중에하고 싶은 작업을 계속하여 계속해서 함수로 전달합니다.

function traverseDocument(node, func, c) {
  var children = node.childNodes;
  function handleChildren(i, c) {
    if (i < children.length)
      traverseDocument(children[i], func,
                       function(){handleChildren(i + 1, c);});
    else
      c();
  }
  return func(node, function(){handleChildren(0, c);});
}

function capitaliseText(node, c) {
  if (node.nodeType == 3)
    node.nodeValue = node.nodeValue.toUpperCase();
  c();
}

traverseDocument(document.body, capitaliseText, function(){});

우리가 자본화 할 huuuuge 문서가 있다고 상상해보십시오. 한 번에 그것을 가로 지르는 것만으로 5 초가 걸리고 5 초 동안 브라우저를 얼리는 것은 다소 나쁜 스타일입니다. 이 간단한 CapitalSeetext 수정을 고려하십시오 (못생긴 글로벌에주의를 기울이지 마십시오) :

var nodeCounter = 0;
function capitaliseText(node, c) {
  if (node.nodeType == 3)
    node.nodeValue = node.nodeValue.toUpperCase();

  nodeCounter++;
  if (nodeCounter % 20 == 0)
    setTimeout(c, 100);
  else
    c();
}

이제 20 개의 노드마다 계산이 100 밀리 초에 중단되어 브라우저 인터페이스에 사용자 입력에 응답 할 수있는 순간을 제공합니다. 매우 원시적 인 스레딩 형태 - 이와 같이 여러 계산을 동시에 실행할 수도 있습니다.

이것의보다 일반적으로 유용한 적용은 xmlhttprequests 또는이를 시뮬레이션하는 데 사용되는 다양한 iframe 및 스크립트 태그 핵과 관련이 있습니다. 이들은 항상 서버가 다시 보낸 데이터를 처리하기 위해 일종의 콜백 메커니즘으로 작동해야합니다. 간단한 경우, 사소한 기능이 수행되거나 몇 가지 글로벌을 사용하여 데이터가 다시 등장한 후 재개 해야하는 계산 상태를 저장할 수 있습니다. 복잡한 경우, 예를 들어, 데이터가 호출자에게 일부 값을 반환 해야하는 함수로 데이터를 사용하는 경우 연속은 상당히 단순화됩니다. 연속을 콜백으로 등록하면 요청이 완료되면 계산이 재개됩니다.

다른 팁

그것을 C와 비교하기 위해, 현재 연속은 스택의 현재 상태와 같습니다. 현재 기능의 결과가 완료되기를 기다리는 모든 기능이있어 실행을 재개 할 수 있습니다. 전류 연속으로 캡처 된 변수는 제공된 값을 가져 와서 대기 스택으로 반환한다는 점을 제외하고는 함수처럼 사용됩니다. 이 동작은 C 함수와 유사합니다 longjmp 스택의 하단 부분으로 즉시 돌아올 수 있습니다.

(define x 0) ; dummy value - will be used to store continuation later

(+ 2 (call/cc (lambda (cc)
                (set! x cc)  ; set x to the continuation cc; namely, (+ 2 _)
                3)))         ; returns 5

(x 4) ; returns 6

C 스택과 연속의 주요 차이점 중 하나는 스택 상태가 변경된 경우에도 프로그램의 어느 시점에서도 연속을 사용할 수 있다는 것입니다. 즉, 이전 버전의 스택을 다시 복원하여 반복해서 사용하여 고유 한 프로그램 흐름을 초래할 수 있습니다.

(* 123 (+ 345 (* 789 (x 5)))) ; returns 7

  reason: it is because (x 5) replaces the existing continuation,
          (* 123 (+ 345 (* 789 _))), with x, (+ 2 _), and returns
          5 to x, creating (+ 2 5), or 7.

프로그램 상태를 저장하고 복원하는 기능은 멀티 스레딩과 공통적입니다. 실제로, 당신은 내가 설명하려고 시도한 것처럼 연속화를 사용하여 자신의 스레드 스케줄러를 구현할 수 있습니다. 여기.

연속 사용의 사소한 예 단일 프로세서 컴퓨터에서 스레드 (원하는 경우 Fiber) 관리자를 구현합니다. 스케줄러는 실행 흐름을 주기적으로 방해합니다 (또는 섬유의 경우 코드의 다양한 전략 지점에서 호출). 연속 상태 (에 해당 현재 스레드), 그런 다음 다른 것으로 전환하십시오 연속 상태 (이전에 상태가 저장된 다른 실에 해당합니다.)

조립 배경을 언급하고 연속 상태는 명령어 포인터, 레지스터 및 스택 컨텍스트 (포인터)와 같은 세부 사항을 캡처합니다., 마음대로 구원 받고 복원해야합니다.

연속을 사용하는 또 다른 방법은 다음과 같습니다 메소드 호출을 여러 스레드와 같은 엔티티로 바꾸는 것을 생각해보십시오 '클래식'대신 연속 컨텍스트를 사용하여 서로 통제하는 통과 통과 (실행 또는 중단) 공존합니다. call 어형 변화표. 매개 변수에 의존하는 대신 글로벌 (공유) 데이터에서 작동합니다. 이것은 어느 정도보다 유연합니다 call 스택이 감을 필요가 없다는 의미에서calls ~이다 중첩), 그러나 제어는 임의로 통과 할 수 있습니다.

이 개념을 시각화하려고합니다 C와 같은 언어로, 하나의 큰 루프를 하나씩 있다고 상상해보십시오. switch(continuation_point) { case point1: ... } 각각의 진술 case 연속 사도 포인트와 각각의 코드가 각각에 해당합니다. case 값을 변경할 수 있습니다 continuation_point 그리고 그것에 대한 통제력을 포기합니다 continuation_point ~에 의해 breaking switch 루프에서 다음 반복을 참여시킵니다.

질문의 맥락은 무엇입니까? 관심있는 특정 시나리오가 있습니까? 특정 프로그래밍 언어가 있습니까? 스레드/섬유 예가 위의 충분한가요?

저를 도와 준 것은 기능을 가진 전통적인 언어에서 당신이 함수 호출을 할 때마다 암시 적으로 계속해서 통과한다는 생각입니다.

함수의 코드로 점프하기 전에 스택에 일부 상태를 저장합니다 (예 : 리턴 주소를 누르면 스택에는 이미 현지인이 포함되어 있음). 이것은 본질적으로 연속입니다. 함수가 완료되면 실행 흐름을 보낼 위치를 결정해야합니다. 스택에 저장된 연속을 사용하여 리턴 주소를 터 뜨리고 점프합니다.

다른 언어는 기능 호출이 이루어진 곳에서 암시 적으로 계속 진행하기보다는 코드 실행을 계속할 위치를 명시 적으로 지정할 수 있도록하는 연속성에 대한이 아이디어를 일반화합니다.

주석에 따라 편집 :

연속은 완전한 실행 상태입니다. 실행 시점에서는 프로그램을이 시점까지 실행 한 두 부분 (공간이 아닌 시간)으로 프로그램을 나눌 수 있습니다. "현재 연속"은 "여기에서 실행될 모든 것"입니다 (나머지 프로그램이 수행했을 모든 작업을 수행 할 함수와 같은 종류를 생각할 수 있습니다). 그래서 당신이 제공하는 기능 call/cc 현재까지의 연속을 통과합니다 call/cc 호출되었습니다. 함수는 계속해서 실행을 사용하여 call/cc 문장 (직접 사용하면 간단한 반환을 수행 할 수 있기 때문에 계속해서 다른 무언가로 계속 통과 할 가능성이 높습니다).

Call/CC를 이해하려고 할 때 이것을 찾았습니다. CHITH-CURTHENT-CONTINUATION-COR-C-PROGRAMMERS 페이지가 도움이되었습니다.

내가 본 가장 좋은 설명은 Paul Graham의 저서입니다. LISP에서.

스크립트가 비디오 게임 단계라고 상상해보십시오. Call/CC는 보너스 단계와 같습니다.

parellel between bonus stage and call/cc

당신이 그것을 터치하자마자 당신은 보너스 단계로 전송됩니다 (즉, 호출/cc [f]에 인수로 전달 된 함수의 정의).

보너스 단계는 일반 단계와 다릅니다 일반적으로 그들은 요소가 있기 때문에 (즉, 당신이 그것을 만지면, 당신이 그것을 터치하면 당신은 잃어 버리고 정상 단계로 다시 전송된다는 요소가 있기 때문입니다.

parellel between exit bonus stage and call/cc function args

따라서 많은 것이 있든 상관 없습니다 args, 당신이 그들 중 하나에 도달하면 그 중 하나에 도달 할 때. 그래서 우리의 실행에 도달합니다 (arg 42) 합으로 반환합니다 (+ 42 10).

또한 주목할 가치가있는 몇 가지 말이 있습니다.

  • 모든 기능을 Call/CC와 함께 사용할 수있는 것은 아닙니다. 연속 (함수)을 기대하기 때문에 다음과 같은 F를 가질 수 없습니다.(define f (lambda (k) (+ k 42)) , 당신은 할 수 없기 때문에 sum 기능.
  • 또한 당신은 가질 수 없습니다 (define f (lambda (k) (f 42 10)))연속은 하나의 주장만을 기대하기 때문입니다.
  • 당신은없이 끝낼 수 있습니다 touching 모든 종료,이 경우 함수는 일반적인 함수와 같이 진행됩니다 (예 : (define f (lambda (k) 42) 마무리 및 반환 42).

Call/CC를 이해하는 데 여러 수준이 있습니다. 먼저 용어와 메커니즘의 작동 방식을 이해해야합니다. 그런 다음 "실제"프로그래밍에 통화/CC가 사용되는 방법과시기에 대한 이해가 필요합니다.

첫 번째 수준은 CPS를 연구하여 도달 할 수 있지만 대안이 있습니다.

두 번째 레벨의 경우 Friedman의 다음 클래식을 추천합니다.

다니엘 P. 프리드먼. "연속 응용 프로그램 : 초청 튜토리얼". 1988 프로그래밍 언어 원칙 (POPL88). 1988 년 1 월.

fscheme에 대한 Call/CC의 설명 및 구현을 살펴보십시오. http://blogs.msdn.com/b/ashleyf/archive/2010/02/11/turning-your-brain-inside-out-with-continuations.aspx

명령적인 관점에서 연속을 이해하는 데 사용한 모델은 다음 명령어와의 포인터와 결합 된 콜 스택의 사본이라는 것입니다.

Call/CC는 연속을 인수로서 함수 (인수로 전달 됨)를 호출합니다.

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