#lang racket ; similar cu funcția assoc (define (stream-assoc s k) (cond ((stream-empty? s) #f) ((equal? (car (stream-first s)) k) (stream-first s)) (else (stream-assoc (stream-rest s) k)))) ; recursivitate deschisă -- primesc funcția pe care trebuie ; să o apelez când am nevoie de apelul recursiv ; Asta îmi folosește ca să pot introduce prelucrări între pelul curent și următorul (define (open-fibo n rec) (if (<= n 1) n (+ (rec (- n 1)) (rec (- n 2))))) ; fibonacci obișnuit, recursivitate arborescentă (define (fibo n) (open-fibo n fibo)) (define N1 30) (define N 300) (time (fibo N1)) ; fibonacci cu tupling, recursivitate pe coadă (define (fib-tp-t-h n pair) (if (zero? n) (car pair) (fib-tp-t-h (sub1 n) (cons (cdr pair) (+ (car pair) (cdr pair)))) )) (define (fib-tp-t n) (fib-tp-t-h n (cons 0 1))) (time (fib-tp-t N)) ; memoizare pentru funcția f care primește un argument, număr natural ; memo-s-nat primește funcția f de memoizat (care are open recursion și primește argumentul și apoi funcția de apelat recursiv) ; și întoarce o funcție de un argument număr natural, care să fie folosită în locul funcției f (define (memo-s-nat f) (let ([value-s (let build ((n 0)) ; specific un flux de perechi (n . (f n)) care va fi calculat doar pe măsură ce caut în el valori (stream-cons (cons n (f n)) (build (add1 n))))]) (λ (n) (cdr (stream-assoc value-s n))) ; rezultat -- f memoizată, care caută în flux valoarea funcției ; dacă aceasta nu este calculată deja, se va construi fluxul până la valoarea necesară )) (define fibo-memo (memo-s-nat (λ (n) (open-fibo n fibo-memo)))) ; la fiecare apel "recursiv" se va trece prin memo-s-nat (time (fibo-memo N)) ; paranteză: număr variabil de argumente: ;(define (plus . args) (foldl + 0 args)) ; define scurt ;(define plus (λ args (foldl + 0 args))) ; folosire λ (define (memoize-recursive f) ;; Each call to memoize-recursive creates its own private cache. ;; This cache is closed over by the 'memoized-version' function. (let ([cache (make-hash)]) ;; This 'memoized-version' is the function that the user will call (e.g., fib-opt). ;; It's also the 'self' argument that will be passed to 'f' for its recursive calls. (define (memoized-version . args) ; '.args' captures all arguments as a list (define key args) ; The list of arguments serves as the cache key (define cached-result (hash-ref cache key #f)) ; Check if result is in cache (cond [cached-result cached-result] ; If found, return cached result immediately [else ;; If not found, compute it. ;; IMPORTANT: Apply the original function 'f', passing 'memoized-version' ;; as its FIRST argument. This 'memoized-version' is the 'self' ;; that 'f' will use for its own recursive calls. (define result (apply f memoized-version args)) ; <--- This is the crucial part! (hash-set! cache key result) ; Store the newly computed result in the cache result])) memoized-version)) ; Return the memoized function wrapper (define (coin-change rec coins sum) (cond ((zero? sum) 0) ((< sum 0) +inf.0) (else (foldl min +inf.0 (map (λ (c) (add1 (rec coins (- sum c)))) coins))))) (define (coin-change-base coins sum) (coin-change coin-change-base coins sum)) (define coin-change-opt (memoize-recursive coin-change)) (time (coin-change-base '(1 5 10 25) 50)) (time (coin-change-opt '(1 5 10 25) 50)) (time (coin-change-opt '(1 5 10 25) 125))