#lang racket (require "utils.rkt") ;------------------Soluție naivă----------------------- #| ; fibonacci recursiv pur (define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ; soluție modulară, elegantă (define (average-even-fibs n) (let* ((interval (range n)) (fibs (map fib interval)) (even-fibs (filter even? fibs)) (sum (apply + even-fibs)) (len (length even-fibs))) (if (zero? len) 0 (/ sum len)))) (average-even-fibs 10) (average-even-fibs 39) ; 0 1 1 2 3 5 8 13 21 34 |# ;------------------Cu optimizările propuse----------------------- #| (define (fib n) (let loop ((n n) (a 0) (b 1)) (if (zero? n) a (loop (- n 1) b (+ a b))))) (define (average-even-fibs n) (match-let (((list sum len) (foldl (λ (x acc) (let ((f (fib x))) (if (even? f) (match acc ((list s l) (list (+ s f) (add1 l)))) acc))) '(0 0) (range n)))) (if (zero? len) 0 (/ sum len)))) (average-even-fibs 10) (time (average-even-fibs 5000)) |# ;------------------Cu fluxuri----------------------- #| (define fib-stream (let loop ((a 0) (b 1)) (stream-cons a (loop b (+ a b))))) ; Abstractizăm funcția average, ; restaurând expresivitatea funcției principale (define (average s) (match-let (((list sum len) (stream-fold (λ (acc x) (list (+ x (car acc)) (+ 1 (cadr acc)))) '(0 0) s))) (if (zero? len) 0 (/ sum len)))) (define (average-even-fibs n) (average (stream-filter even? (stream-take fib-stream n)))) (average-even-fibs 10) (time (average-even-fibs 5000)) |# ;------------------Cu memoizare----------------------- #| (define fib-cache (make-hash)) (define (fib n) (if (< n 2) n (hash-ref! fib-cache n (λ () (+ (fib (- n 1)) (fib (- n 2))))))) (define (average s) (match (stream-fold (λ (acc x) (list (+ x (car acc)) (+ 1 (cadr acc)))) '(0 0) s) ((list _ 0) 0) ((list sum len) (/ sum len)))) (define (stream-range a b) (if (= a b) empty-stream (stream-cons a (stream-range (add1 a) b)))) (define (average-even-fibs n) (average (stream-filter even? (stream-map fib (stream-range 0 n))))) (average-even-fibs 10) (time (average-even-fibs 5000)) |# ;------------------Cu macro----------------------- #| (define/memo (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (define (average s) (match (stream-fold (λ (acc x) (list (+ x (car acc)) (+ 1 (cadr acc)))) '(0 0) s) ((list _ 0) 0) ((list sum len) (/ sum len)))) (define (stream-range a b) (if (= a b) empty-stream (stream-cons a (stream-range (add1 a) b)))) (define (average-even-fibs n) (average (stream-filter even? (stream-map fib (stream-range 0 n))))) (average-even-fibs 10) (time (average-even-fibs 5000)) |# ;--------------Reutilizare macro------------------------ ; Ex: numărul minim de monede din setul coins ; cu care se poate plăti suma sum (define/memo (coin-change coins sum) (cond ((zero? sum) 0) ((negative? sum) +inf.0) (else (add1 (apply min (map (λ (c) (coin-change coins (- sum c))) coins)))))) ;(map (curry coin-change '(1 5 10 25)) (range 50 61)) ;-------------Programare simbolică---------------------- ; Transformarea în named let, pentru șablonul ;(define (f ...) ; (define (g ...) ; corp-g) ; (g ...)) (define (rewrite-to-named-let expr) (match expr ((list 'define (cons f args) (list 'define (cons g args-g) body) (cons g-call expressions)) #:when (eq? g g-call) `(define ,(cons f args) (let ,g ,(map list args-g expressions) ,body))))) (define code-fact '(define (fact n) (define (helper n acc) (if (zero? n) acc (helper (- n 1) (* n acc)))) (helper n 1))) (define code-fib '(define (fib n) (define (helper n a b) (if (zero? n) a (helper (- n 1) b (+ a b)))) (helper n 0 1))) (rewrite-to-named-let code-fact) (rewrite-to-named-let code-fib) ;(define (fib n) ; (let helper ((n n) (a 0) (b 1)) (if (zero? n) a (helper (- n 1) b (+ a b))))) ;(map fib (range 10))