2010-01-07 2 views
41

나는 와 함께 일하고있다 Little Schemer 스킴을 배우고 제 환경에 PLT-Scheme을 사용합니다. 작은 고안자 스킴의 연속을 이해하는 것을 돕기

재귀와 함께 엄청난 도움이되었습니다 (지금 나를 위해 간단합니다) 그러나 나는 "집"을 소개하고 연속 전체 함수를 호출하는 책의 일부에 갇혔어요.

다음은 사용 된 예제 코드입니다. 나는 재귀적인 요소를 이해하지만, 특히 람다 함수에 붙어있다. 내 마음이 경로를 따라갈 수없고, 그 람다 함수에 대한 인수가 어떻게 설정되어 있는가? (유일한 호출은 재귀에서 다시 호출하는 것이기 때문에, 함수 본문 내에서 구체적인 사용이 없음).

누군가가 람다 수집기로 함수를 재귀하여 계산 경로를 무너 뜨릴 수 있다면 나를 도울 수 있습니다.

;; Build a nested list of even numbers by removing the odd ones from its 
;; argument and simultaneously multiply the even numbers and sum the odd 
;; numbers that occur in its argument. 
(define (even-only-collector l col) 
    (cond 
    ((null? l) 
     (col (quote()) 1 0)) 
    ((atom? (car l)) 
     (cond 
     ((even? (car l)) 
      (even-only-collector (cdr l) 
      (lambda (newl p s) 
       (col (cons (car l) newl) 
       (* (car l) p) s)))) 
     (else 
      (even-only-collector (cdr l) 
      (lambda (newl p s) 
       (col newl 
       p (+ (car l) s))))))) 
    (else 
     (even-only-collector (car l) 
     (lambda (al ap as) 
      (even-only-collector (cdr l) 
      (lambda (dl dp ds) 
       (col (cons al dl) 
       (* ap dp) 
       (+ as ds))))))))) 

;; The collector function 
(define (collector newl product sum) 
    (cons sum 
    (cons product newl))) 

감사합니다.

+0

@lpthnc : newLISP를 보았습니까? – Ixmatus

답변

41

어떻게 작동하는지 간단하게 살펴보십시오.

(define (list-sum l k) 
    (if (null? l) 
    ??? 
    (list-sum (cdr l) ???))) 

기본 패턴이 존재하고, 흥미로운 일들이 일어날 경우 누락 된 부분은 다음과 같습니다 예를 들어, 다음 (보통 k라고합니다) 연속 인수를받는 list-sum 기능의 버전입니다. 계속 인수는 결과를 받아야하는 기능입니다 - 그래서리스트가 null의 경우 그 합이기 때문에, 우리가 그것을 0를 보내야 분명하다 : 이제

(define (list-sum l k) 
    (if (null? l) 
    (k 0) 
    (list-sum (cdr l) ???))) 

목록이없는 경우, null이면, 우리는리스트의 꼬리를 가지고 반복적으로 함수를 호출한다. (다시 말하면 iteration이다.)하지만 계속되어야하는 것은 무엇인가이다. 이렇게 :

(define (list-sum l k) 
    (if (null? l) 
    (k 0) 
    (list-sum (cdr l) k))) 

하는 것은 분명히 잘못된 것입니다 - 그것은 k 결국 대신 l의 모든 (cdr l)의 합을 받게된다는 것을 의미합니다. 이 가까워지고있다

(define (list-sum l k) 
    (if (null? l) 
    (k 0) 
    (list-sum (cdr l) (lambda (sum) (+ (car l) sum))))) 

,하지만 여전히 잘못 대신, 너무가 수신하는 값과 함께 l의 첫 번째 요소를 요약되는,이 새로운 기능을 사용하십시오. 그러나 일이 어떻게 진행되고 있는지 생각하는 것은 좋은 지적입니다. 우리는 list-sum에 계속해서 전체 합계를 받고, 지금 보았던 첫 번째 항목을 추가 할 것입니다. 누락 된 부분은 우리가 k을 무시한다는 사실에서 분명합니다.이 기능을k를 작성하려면 우리에게 필요한 것은 - 그래서 우리가 같은 금액의 작업을 수행 한 후 k에 결과를 보내 : 마지막으로하고있다

(define (list-sum l k) 
    (if (null? l) 
    (k 0) 
    (list-sum (cdr l) (compose k (lambda (s) (+ s (car l))))))) 

합니다. (BTW,이 lambda 각 기능이 l 자체 "복사"를 가지고 있음을 기억하십시오.) 당신은 이것을 시도 할 수 있습니다 :

(list-sum '(1 2 3 4) (lambda (x) x)) 

그리고 마지막으로이 같은이므로주의 :

(define (list-sum l k) 
    (if (null? l) 
    (k 0) 
    (list-sum (cdr l) (lambda (s) (k (+ s (car l))))))) 

컴포지션을 명시 적으로 지정하면됩니다.

(중간 + 람다 학생용 언어로이 코드를 사용하고 스테퍼 버튼을 클릭하여 평가가 진행되는 과정을 볼 수도 있습니다.이 작업은 다소 시간이 걸리지 만 계속 기능 중첩되어 각리스트는 자신 만의 뷰입니다.)

+0

정말 고마워요, 제가 찾고 있던 답변입니다. 스테퍼의 팁이 특히 도움이됩니다. 고맙습니다! – Ixmatus

+0

방금 ​​람다 언어와 스테퍼로 중급 학생과 연습을했습니다. 얼마나 도움이되는지 당신에게 말할 수는 없습니다. 그렇게해서 실행의 길을 볼 수있게되어 모든 혼란을 해결했습니다 !! 대단히 감사합니다. – Ixmatus

+0

예 - "학생용 도구"로 종종 과소 평가되는 도구입니다 ... –

1

"좀 더 구체적인 아이디어"를 얻는 데 도움이되는 한 가지 방법이 있습니다. 콜렉터가 이렇게 정의 된 상상해 :

(define (collector l p s) 
    (display l) 
    (newline) 
    (display p) 
    (newline) 
    (display s) 
    (newline)) 

당신은 빈 목록에 전달하면, 그것은으로 지금 일을 당신의 인수 '(), 1 기능, 0을 호출, 기본 케이스에서 볼 수 하나의 요소로 구성된 목록을 작성하고 귀하의 기능을 호출하는 부분을 확인하십시오. 진행 상황을 파악할 때까지 길고 긴 목록으로 계속 작업하십시오.

행운을 빈다.

+0

고맙습니다. – Ixmatus

+0

그래서 나는 빈 목록을 통과 할 때 어떤 일이 발생 하는지를 정확히 이해하고 더 작고 연속적으로 큰 목록을 전달할 때 어떤 일이 벌어지는지를 볼 수 있습니다. 하지만 나는 그들의 몸을위한 컬렉터가있는 람다 식의 "방법"을 파악하지 못했습니다 ... – Ixmatus

+0

객체 지향 언어로 작업 한 적이 있습니까? 그렇다면 데코레이터 패턴에 대해 들어 보셨습니까? 각 람다는 기본적으로 수집기를 하나 더 레이어로 꾸미고 있습니다. –

관련 문제