스킴의 “let”을 이해하려고 노력 중
문제
간단한 피보나치 함수를 확장하려고 하는데 각 항의 값을 두 번 이상 사용해야 합니다.그래서 나는 내가 사용할 것이라고 생각했습니다. let
가치를 붙잡기 위해.그러나 나는 그 기능에서 내가 생각해야 할 것을 얻지 못하고 있습니다.
여기 원본이 있습니다 fib
기능:
(define (fib n)
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
여기에 같은 일을 하려는 나의 시도가 있습니다. let
:
(define (fib-with-let n)
(if (< n 2)
0
(let ((f1 (fib-with-let (- n 1)))
(f2 (fib-with-let (- n 2))))
(+ f1 f2))))
결과:
> (fib 10)
55
> (fib-with-let 10)
0
감사해요!
해결책
오타를 냈습니다:
(if (< n 2)
0
...)
네 말 뜻은 n
.
다른 팁
기본 케이스를 잘못 입력했습니다.첫 번째 버전 : 라코 디스
하지만 후자의 버전에서는 다음과 같이 썼습니다. 라코 디스
그러므로 0
를 n
로 변경하세요.
당신의 let은 실제로 아무것도하지 않습니다. 여전히 모든 추가 계산을 수행하고 있습니다. f1
를 (fib-with-let (- n 1))
로 정의한다고해서 n-1의 fib를 다시 계산하지 않는다는 의미는 아닙니다. f2
는 f1
를 사용하지 않습니다 . f2
가 f1
를 보도록 원한다면 let*
를 사용할 것입니다. 그러나 이것은 실제로 원하는 것이 아닙니다.
이에 대한 증거로서 다음은 for fib(35)
및 fib-with-let(35)
의 실행 시간입니다.
라코 디스
추가 계산을 피하기 위해 정말로 원하는 것은 동적 프로그래밍 을 사용하고 재귀하는 것입니다. 상향식 .
원하는 것은 다음 코드입니다. 라코 디스
보시다시피 순진한 접근 방식이 걸리는 시간의 3 분의 1에 처음 150,000 개의 fib를 수행 할 수 있습니다. <시간>
let이 무엇을 더 잘 설명 할 수 있는지에 대해 혼란스러워 보이기 때문에
말할 때 : 라코 디스
말하고있는 것은 a를 1로, b를 2로하여 합산하는 것입니다. 대신 다음과 같이 말한 경우 : 라코 디스
무엇을 얻을 수 있을지 짐작할 수 있습니까? 아니 3. expand: unbound identifier in module in: a
로 폭발 할 것입니다.
간단한 let
에서는 과제가 서로 볼 수 없습니다.
위의 내용을 작성하려면 let*
를 사용해야합니다.
라코 디스
그렇게하면 예상 한 3 가지를 얻을 수 있습니다. let*
는 기본적으로 다음으로 확장됩니다.
라코 디스
<시간>
당신이 Let 's로하고 있다고 생각한 것을 memoization 이라고합니다. 반복 할 필요가 없도록 중간 값을 저장하는 기술입니다. 하지만 그렇게하지 마십시오.
문제가 fib-with-let
함수의 오타이지만 가장 간단한 형식으로 let
는 익명의 람다에 대해 "syntatic-sugar"이고 그 뒤에 인수가 평가되고 람 바로 전달 된 다음 평가되고최종 값이 반환되었습니다.그래서
라코 디스
다음처럼 보이도록 let
없이 다시 작성 될 것입니다.
라코 디스