문제

나는 Lisp 초보자.내가 노력하고,그러나 다른 클라이언트 재귀적 기능에 대한 계산을 수의 약관 Collatz 순서 (문제에 대한 14 프로젝트의 오일러).내 코드는 아직입니다:

(defun collatz-steps (n)
  (if (= 1 n) 0
       (if (evenp n) 
           (1+ (collatz-steps (/ n 2)))
           (1+ (collatz-steps (1+ (* 3 n)))))))

(defun p14 ()
  (defvar m-collatz-steps (memoize #'collatz-steps))
  (let 
      ((maxsteps (funcall m-collatz-steps 2))
       (n 2)
       (steps))
    (loop for i from 1 to 1000000
          do 
          (setq steps (funcall m-collatz-steps i))
          (cond 
            ((> steps maxsteps) 
             (setq maxsteps steps)
             (setq n i))
            (t ())))
    n))


(defun memoize (fn)
  (let ((cache (make-hash-table :test #'equal)))
    #'(lambda (&rest args)
        (multiple-value-bind 
              (result exists)
            (gethash args cache)
          (if exists
              result
              (setf (gethash args cache)
                    (apply fn args)))))))

은,그러나 다른 클라이언트 기능 같은 주어진 하나에 에 Lisp 책입니다.

이 코드를 하지 않는 실제로 어떤 속도에 비해 비 memoized 버전입니다.나는 그것을 믿는 것 때문에 재귀적 전화 통화 비 memoized 버전의 기능절적으로 사용할 수 있습니다.이 경우에는 무엇을 할 수 있는 올바른 방법의 메모이 제이션까요?하는 방법은 없는 모든 통화를 원래의 함수를 호출 memoized 버전 자체를 제거에 필요한 특별한 m-collatz 단계가 있습니다.

편집:정 코드를 갖

(defvar m-collatz-steps (memoize #'collatz-steps))

는 것에 있었던 나의 코드입니다.기 전에 편집 나는 잘못을 넣어:

(defvar collatz-steps (memoize #'collatz-steps))

보고는 오류가 나에게 준 또 다른 아이디어,그리고 나는 시도를 사용하여 이 지속 defvar 자체와 변경하는 재귀한 통화

       (1+ (funcall collatz-steps (/ n 2)))
       (1+ (funcall collatz-steps (1+ (* 3 n))))

이 않을 수행하는 메모이 제이션(속도에서 약 60 초을 1.5 초)지만,필요한 변화의 본래 기능입니다.가 깨끗한 솔루션을 포함하지 않는 원본을 변경하는 기능?

도움이 되었습니까?

해결책

나는 가정 당신이 사용하는 일반적-Lisp,는 별도의 네임스페이스를 위한 변수 함수 이름.기 위해서는,그러나 다른 클라이언트 기능에 의해 지명은 기호를 변경해야 합니다 그 기능을 바인딩을 통해 접근자`fdefinition':

(setf (fdefinition 'collatz-steps) (memoize #'collatz-steps))

(defun p14 ()
  (let ((mx 0) (my 0))
    (loop for x from 1 to 1000000
          for y = (collatz-steps x)
          when (< my y) do (setf my y mx x))
    mx))

다른 팁

무언가 이것을 좋아한다:

(setf collatz-steps (memoize lambda (n)
  (if (= 1 n) 0
    (if (evenp n) 
        (1+ (collatz-steps (/ n 2)))
        (1+ (collatz-steps (1+ (* 3 n))))))))

IOW:서 원본(비 memoized)함수는 익명으로,당신은 단지의 이름을 제공하는 결과의 memoizing 니다.

여기에,그러나 다른 클라이언트 기능을 다시 바인딩 기호 기능:

(defun memoize-function (function-name)
  (setf (symbol-function function-name)
    (let ((cache (make-hash-table :test #'equal)))
         #'(lambda (&rest args)
             (multiple-value-bind 
                 (result exists)
                (gethash args cache)
               (if exists
                   result
                   (setf (gethash args cache)
                         (apply fn args)))))))

그러면 다음과 같은 것이 가능합니다.

(defun collatz-steps (n)
  (if (= 1 n) 0
      (if (evenp n) 
          (1+ (collatz-steps (/ n 2)))
          (1+ (collatz-steps (1+ (* 3 n)))))))

(memoize-function 'collatz-steps)

나는 그것을 떠날 당신이 unmemoize-기능입니다.

변경은"원래는"기능이 필요하기 때문에,당신 말대로,다른 방법이 없을 위한 재귀화(s)를 업데이트를 호출하 memoized 버전입니다.

다행히도,방법 lisp 작품을 찾는 것이 기능 이름 각 시간을 필요가 호출됩니다.즉 그것은 충분한 기능을 대체하는 바인딩을 가진 memoized 버전의 기능도록,재귀적인 통화를 자동적으로 찾고 다시 입력을 통해서 메모이 제이션.

화이 위안 코드를 보여줍니다 중요한 단계:

(setf (fdefinition 'collatz-steps) (memoize #'collatz-steps))

이 속도에서 작동 Perl.에서 같은 언어진다,그러나,memoized 버전의 함수 코드화되어야 합니다.

일부 패키지 구현에서는 시스템을 제공하라""조언을 제공하는 표준화된 구조를 대체를 위해 기능을 향상된 버전의 자체.또한 기능 업그레이드 같은 메모이 제이션이 될 수 있습니다 매우 유용한 디버깅에 삽입하여 디버그 인쇄(또는 완전히 중지 및 주연속적 프롬프트)를 수정하지 않고 원래 코드입니다.

다음 사항을 확인하십시오:

(defun foo (bar)
   ... (foo 3) ...)

상은 함수가 호출됩니다.

에서 공통적인 파일을 컴파일러는 가정 할 수 있습 FOO 변경되지 않습니다.그것이 부르지 않을 것입 업데이트 FOO 니다.을 변경하는 경우 기능의 결합 FOO,다음의 전화를 본래의 기능을 것입니다 여전히 오래된 기능이다.

그래서 memoizing 자체 재귀적인 기능이 작동하지 않습니다 일반적인 경우에.특히지 않는 경우에 당신은 좋은을 사용하여 컴파일러입니다.

작업할 수 있습니다 그것은 항상 이동 상징을 통해 예를 들어:(funcall'foo3)

(DEFVAR...)은 최고 수준의 형태입니다.그것을 사용하지 않 내부 기능이 있다.만약 당신이 선언된 변수 설정,그것 SETQ 또는 SETF 니다.

에 대한 문제가 해시 테이블을 사용하는 저장소 중간 결과입니다.

이 기능은 정확하게 하나 베드로는 노르 빅을 제공합의 예로서 기능하는 것 같아 좋은 후보에 대한 메모이 제이션,그러하지 않습니다.

그림 3 참조(이 기능은'충격')그래에 종이 메모이 제이션("사용하여 자동으로 메모이 제이션으로 소프트웨어 공학 도구에서 실제 AI 시스템").

그래서 나는 추측을 얻을 경우에도 역학의 메모이 제이션 작업하지 않습니다,정말속에서 그것을 이 경우입니다.

얼마 전에 내가 쓴 메모이 제이션 작은 일상에 대한 계획을 사용한 체인의 마감을 추적합 memoized 상태:

(define (memoize op)
  (letrec ((get (lambda (key) (list #f)))
           (set (lambda (key item)
                  (let ((old-get get))
                    (set! get (lambda (new-key)
                                (if (equal? key new-key) (cons #t item)
                                    (old-get new-key))))))))
    (lambda args
      (let ((ans (get args)))
        (if (car ans) (cdr ans)
            (let ((new-ans (apply op args)))
              (set args new-ans)
              new-ans))))))

이처럼 사용할 수 있도록:

(define fib (memoize (lambda (x)
                       (if (< x 2) x
                           (+ (fib (- x 1)) (fib (- x 2)))))))

나는 이에 이식할 수 있습니다 당신의 마음에 드는 어휘가 범위 Lisp 맛습니다.

나는 아마 다음과 같습니다.

(let ((memo (make-hash-table :test #'equal)))
  (defun collatz-steps (n)
    (or (gethash n memo)
    (setf (gethash n memo)
          (cond ((= n 1) 0)
            ((oddp n) (1+ (collatz-steps (+ 1 n n n))))
            (t (1+ (collatz-steps (/ n 2)))))))))

그것은 좋은 기능성,하지만,그런 다음,그것은 많지 않은 번거 로움과 작업을 수행합니다.단점은 얻을 수 없는 편리한 unmemoized 버전을 테스트하고 캐시를 삭제하는 경계에서"아주 어렵다".

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